summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Cherry <tcherry@nvidia.com>2012-05-23 12:06:13 -0700
committerTom Cherry <tcherry@nvidia.com>2012-05-23 12:06:13 -0700
commita168c03bd97fd9761218779623db0cec09fa8f4a (patch)
tree521d2b51904da963d771c24fd9b142cc416f8259 /drivers
parent11fb7d0e35d56230919eb91bee1aa138a10b8416 (diff)
parentc7e3189c1802c2a6552eec960f521a1891529892 (diff)
Merge commit 'main-ics-2012.05.22-B3' into HEAD
Conflicts: arch/arm/mach-tegra/pm.c drivers/media/video/tegra/nvavp/nvavp_dev.c drivers/power/smb349-charger.c include/linux/smb349-charger.h include/trace/events/power.h Change-Id: Ia8c82e2acfe3463ae6778bdd03aac8da104f7ad3
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/regmap/Kconfig3
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/internal.h24
-rw-r--r--drivers/base/regmap/regcache-lzo.c27
-rw-r--r--drivers/base/regmap/regcache-rbtree.c79
-rw-r--r--drivers/base/regmap/regcache.c113
-rw-r--r--drivers/base/regmap/regmap-debugfs.c93
-rw-r--r--drivers/base/regmap/regmap-i2c.c13
-rw-r--r--drivers/base/regmap/regmap-irq.c37
-rw-r--r--drivers/base/regmap/regmap-mmio.c224
-rw-r--r--drivers/base/regmap/regmap-spi.c13
-rw-r--r--drivers/base/regmap/regmap.c234
-rw-r--r--drivers/bluetooth/ti_bluesleep.c120
-rw-r--r--drivers/clk/clkdev.c45
-rw-r--r--drivers/cpufreq/cpufreq.c57
-rw-r--r--drivers/crypto/tegra-aes.c11
-rw-r--r--drivers/gpio/gpio-tegra.c14
-rw-r--r--drivers/gpu/ion/tegra/tegra_ion.c2
-rw-r--r--drivers/hid/hid-sony.c25
-rw-r--r--drivers/hwmon/tegra-tsensor.c4
-rw-r--r--drivers/i2c/busses/i2c-tegra.c40
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_bus.c16
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_f09.c20
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_spi.c13
-rw-r--r--drivers/iommu/tegra-gart.c2
-rw-r--r--drivers/iommu/tegra-smmu.c2
-rw-r--r--drivers/media/video/tegra/Kconfig7
-rw-r--r--drivers/media/video/tegra/Makefile1
-rw-r--r--drivers/media/video/tegra/ad5820.c2
-rw-r--r--drivers/media/video/tegra/ar0832_main.c9
-rw-r--r--drivers/media/video/tegra/avp/avp.c2
-rw-r--r--drivers/media/video/tegra/avp/avp_svc.c2
-rw-r--r--drivers/media/video/tegra/nvavp/nvavp_dev.c48
-rw-r--r--drivers/media/video/tegra/ov14810.c2
-rw-r--r--drivers/media/video/tegra/ov2710.c2
-rw-r--r--drivers/media/video/tegra/ov5640.c491
-rw-r--r--drivers/media/video/tegra/ov5640_tables.h4582
-rw-r--r--drivers/media/video/tegra/ov5650.c98
-rw-r--r--drivers/media/video/tegra/ov9726.c1
-rw-r--r--drivers/media/video/tegra/sh532u.c871
-rw-r--r--drivers/media/video/tegra/soc380.c1
-rw-r--r--drivers/media/video/tegra/tegra_camera.c306
-rw-r--r--drivers/mfd/max77663-core.c8
-rw-r--r--drivers/mfd/max8907c.c15
-rw-r--r--drivers/mfd/tps80031.c18
-rw-r--r--drivers/misc/bcm4329_rfkill.c7
-rw-r--r--drivers/misc/nct1008.c38
-rw-r--r--drivers/misc/tegra-cryptodev.c173
-rw-r--r--drivers/misc/tegra-cryptodev.h15
-rw-r--r--drivers/mmc/card/Kconfig10
-rw-r--r--drivers/mmc/card/block.c3
-rw-r--r--drivers/mmc/card/mmc_test.c2
-rw-r--r--drivers/mmc/core/core.c5
-rw-r--r--drivers/mmc/core/mmc_ops.c2
-rw-r--r--drivers/mmc/host/sdhci-tegra.c83
-rw-r--r--drivers/mmc/host/sdhci.c28
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mmc/host/sh_mmcif.c5
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c5
-rw-r--r--drivers/mtd/maps/tegra_nor.c2
-rw-r--r--drivers/net/usb/cdc_ether.c9
-rw-r--r--drivers/net/usb/cdc_subset.c5
-rw-r--r--drivers/net/usb/raw_ip_net.c191
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile3
-rw-r--r--drivers/net/wireless/bcmdhd/Kconfig7
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile4
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c2
-rw-r--r--drivers/net/wireless/sd8797/Kconfig39
-rw-r--r--drivers/net/wireless/sd8797/Makefile176
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan.h35
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11d.c1515
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11h.c3208
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11h.h158
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n.c1936
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n.h420
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c509
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h37
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c1138
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h102
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_cfp.c1378
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c2934
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_decl.h893
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_fw.h4672
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_ieee.h1322
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_init.c1043
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_init.h88
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_ioctl.h2981
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_join.c1853
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_join.h40
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_main.h2742
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_meas.c464
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_meas.h54
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_misc.c2156
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_module.c47
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_scan.c4223
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sdio.c1661
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sdio.h307
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_shim.c946
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c1996
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c1726
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_event.c589
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c5489
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c289
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c277
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_txrx.c376
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap.h104
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c3021
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c1393
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c556
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_util.h526
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_wmm.c2521
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_wmm.h182
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan.h35
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan_decl.h893
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan_ieee.h1322
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h2981
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c1687
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h203
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_debug.c674
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c2176
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h90
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_ioctl.c4463
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_main.c4036
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_main.h1564
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_priv.c6690
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_priv.h729
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_proc.c631
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sdio.h140
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c734
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_shim.c1527
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_shim.h95
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c2520
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h41
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap.c2692
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap.h410
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c1288
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h30
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c175
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h194
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c1766
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_wext.c3051
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_wext.h115
-rw-r--r--drivers/power/bq27x00_battery.c6
-rw-r--r--drivers/power/max17048_battery.c31
-rw-r--r--drivers/power/smb349-charger.c42
-rw-r--r--drivers/regulator/Kconfig19
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/core.c62
-rw-r--r--drivers/regulator/max77663-regulator.c12
-rw-r--r--drivers/regulator/max8973-regulator.c606
-rw-r--r--drivers/regulator/tps6238x0-regulator.c470
-rw-r--r--drivers/rtc/rtc-tps6591x.c90
-rw-r--r--drivers/spi/spi-tegra.c22
-rw-r--r--drivers/spi/spi-topcliff-pch.c5
-rw-r--r--drivers/tty/serial/amba-pl011.c5
-rw-r--r--drivers/tty/serial/pch_uart.c5
-rw-r--r--drivers/tty/serial/sh-sci.c5
-rw-r--r--drivers/tty/serial/tegra_hsuart.c2
-rw-r--r--drivers/usb/class/cdc-acm.c16
-rw-r--r--drivers/usb/gadget/Kconfig11
-rw-r--r--drivers/usb/gadget/Makefile4
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c200
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h3
-rw-r--r--drivers/usb/gadget/gadget_chips.h4
-rw-r--r--drivers/usb/gadget/tegra_udc.c2867
-rw-r--r--drivers/usb/gadget/tegra_udc.h440
-rw-r--r--drivers/usb/gadget/udc-core.c4
-rw-r--r--drivers/usb/host/ehci-tegra.c100
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/otg/tegra-otg.c269
-rw-r--r--drivers/usb/serial/baseband_usb_chr.c548
-rw-r--r--drivers/usb/serial/baseband_usb_chr.h9
-rw-r--r--drivers/video/mx3fb.c5
-rw-r--r--drivers/video/tegra/Kconfig18
-rw-r--r--drivers/video/tegra/dc/Makefile1
-rw-r--r--drivers/video/tegra/dc/dc.c374
-rw-r--r--drivers/video/tegra/dc/dc_config.c246
-rw-r--r--drivers/video/tegra/dc/dc_config.h148
-rw-r--r--drivers/video/tegra/dc/dc_priv.h19
-rw-r--r--drivers/video/tegra/dc/dc_reg.h6
-rw-r--r--drivers/video/tegra/dc/dsi.c128
-rw-r--r--drivers/video/tegra/dc/ext/Makefile1
-rw-r--r--drivers/video/tegra/dc/ext/dev.c41
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h2
-rw-r--r--drivers/video/tegra/dc/ext/util.c2
-rw-r--r--drivers/video/tegra/dc/hdmi.c182
-rw-r--r--drivers/video/tegra/dc/rgb.c8
-rw-r--r--drivers/video/tegra/fb.c53
-rw-r--r--drivers/video/tegra/host/Makefile3
-rw-r--r--drivers/video/tegra/host/bus.c82
-rw-r--r--drivers/video/tegra/host/bus.h38
-rw-r--r--drivers/video/tegra/host/bus_client.c72
-rw-r--r--drivers/video/tegra/host/chip_support.c56
-rw-r--r--drivers/video/tegra/host/chip_support.h33
-rw-r--r--drivers/video/tegra/host/debug.c20
-rw-r--r--drivers/video/tegra/host/dev.c96
-rw-r--r--drivers/video/tegra/host/dev.h16
-rw-r--r--drivers/video/tegra/host/dsi/dsi.c3
-rw-r--r--drivers/video/tegra/host/gr2d/gr2d.c3
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.c85
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.c6
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c8
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c203
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.h2
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.c21
-rw-r--r--drivers/video/tegra/host/host1x/host1x_debug.c17
-rw-r--r--drivers/video/tegra/host/host1x/host1x_hwctx.h1
-rw-r--r--drivers/video/tegra/host/host1x/host1x_intr.c77
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.c34
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.h5
-rw-r--r--drivers/video/tegra/host/isp/isp.c3
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c61
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c55
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c142
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h10
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c49
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h35
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h2
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c48
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h1
-rw-r--r--drivers/video/tegra/host/nvhost_job.c7
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c55
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h11
-rw-r--r--drivers/video/tegra/host/t20/t20.c71
-rw-r--r--drivers/video/tegra/host/t20/t20.h11
-rw-r--r--drivers/video/tegra/host/t30/t30.c84
-rw-r--r--drivers/video/tegra/host/t30/t30.h9
-rw-r--r--drivers/video/tegra/host/vi/vi.c3
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap.h10
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c6
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c33
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.h2
236 files changed, 115663 insertions, 2400 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 0f6c7fb..9ef0a53 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -14,5 +14,8 @@ config REGMAP_I2C
config REGMAP_SPI
tristate
+config REGMAP_MMIO
+ tristate
+
config REGMAP_IRQ
bool
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index defd579..5e75d1b 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
+obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index abd7667..d92e9b1 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -26,21 +26,29 @@ struct regmap_format {
size_t val_bytes;
void (*format_write)(struct regmap *map,
unsigned int reg, unsigned int val);
- void (*format_reg)(void *buf, unsigned int reg);
- void (*format_val)(void *buf, unsigned int val);
+ void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
+ void (*format_val)(void *buf, unsigned int val, unsigned int shift);
unsigned int (*parse_val)(void *buf);
};
+typedef void (*regmap_lock)(struct regmap *map);
+typedef void (*regmap_unlock)(struct regmap *map);
+
struct regmap {
- struct mutex lock;
+ struct mutex mutex;
+ spinlock_t spinlock;
+ regmap_lock lock;
+ regmap_unlock unlock;
struct device *dev; /* Device we do I/O on */
void *work_buf; /* Scratch buffer used to format I/O */
struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus;
+ void *bus_context;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
+ const char *debugfs_name;
#endif
unsigned int max_register;
@@ -52,6 +60,10 @@ struct regmap {
u8 read_flag_mask;
u8 write_flag_mask;
+ /* number of bits to (left) shift the reg value when formatting*/
+ int reg_shift;
+ int reg_stride;
+
/* regcache specific members */
const struct regcache_ops *cache_ops;
enum regcache_type cache_type;
@@ -88,7 +100,7 @@ struct regcache_ops {
int (*exit)(struct regmap *map);
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
- int (*sync)(struct regmap *map);
+ int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
};
bool regmap_writeable(struct regmap *map, unsigned int reg);
@@ -101,11 +113,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
#ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void);
-extern void regmap_debugfs_init(struct regmap *map);
+extern void regmap_debugfs_init(struct regmap *map, const char *name);
extern void regmap_debugfs_exit(struct regmap *map);
#else
static inline void regmap_debugfs_initcall(void) { }
-static inline void regmap_debugfs_init(struct regmap *map) { }
+static inline void regmap_debugfs_init(struct regmap *map, const char *name) { }
static inline void regmap_debugfs_exit(struct regmap *map) { }
#endif
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index b7d1614..9b36703 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -107,7 +107,7 @@ static int regcache_lzo_decompress_cache_block(struct regmap *map,
static inline int regcache_lzo_get_blkindex(struct regmap *map,
unsigned int reg)
{
- return (reg * map->cache_word_size) /
+ return ((reg / map->reg_stride) * map->cache_word_size) /
DIV_ROUND_UP(map->cache_size_raw,
regcache_lzo_block_count(map));
}
@@ -115,9 +115,10 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map,
static inline int regcache_lzo_get_blkpos(struct regmap *map,
unsigned int reg)
{
- return reg % (DIV_ROUND_UP(map->cache_size_raw,
- regcache_lzo_block_count(map)) /
- map->cache_word_size);
+ return (reg / map->reg_stride) %
+ (DIV_ROUND_UP(map->cache_size_raw,
+ regcache_lzo_block_count(map)) /
+ map->cache_word_size);
}
static inline int regcache_lzo_get_blksize(struct regmap *map)
@@ -321,7 +322,7 @@ static int regcache_lzo_write(struct regmap *map,
}
/* set the bit so we know we have to sync this register */
- set_bit(reg, lzo_block->sync_bmp);
+ set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
kfree(tmp_dst);
kfree(lzo_block->src);
return 0;
@@ -331,7 +332,8 @@ out:
return ret;
}
-static int regcache_lzo_sync(struct regmap *map)
+static int regcache_lzo_sync(struct regmap *map, unsigned int min,
+ unsigned int max)
{
struct regcache_lzo_ctx **lzo_blocks;
unsigned int val;
@@ -339,10 +341,21 @@ static int regcache_lzo_sync(struct regmap *map)
int ret;
lzo_blocks = map->cache;
- for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+ i = min;
+ for_each_set_bit_from(i, lzo_blocks[0]->sync_bmp,
+ lzo_blocks[0]->sync_bmp_nbits) {
+ if (i > max)
+ continue;
+
ret = regcache_read(map, i, &val);
if (ret)
return ret;
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, i);
+ if (ret > 0 && val == map->reg_defaults[ret].def)
+ continue;
+
map->cache_bypass = 1;
ret = _regmap_write(map, i, val);
map->cache_bypass = 0;
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 32620c4..be7b068 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -38,11 +38,12 @@ struct regcache_rbtree_ctx {
};
static inline void regcache_rbtree_get_base_top_reg(
+ struct regmap *map,
struct regcache_rbtree_node *rbnode,
unsigned int *base, unsigned int *top)
{
*base = rbnode->base_reg;
- *top = rbnode->base_reg + rbnode->blklen - 1;
+ *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
}
static unsigned int regcache_rbtree_get_register(
@@ -69,7 +70,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
rbnode = rbtree_ctx->cached_rbnode;
if (rbnode) {
- regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+ &top_reg);
if (reg >= base_reg && reg <= top_reg)
return rbnode;
}
@@ -77,7 +79,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
node = rbtree_ctx->root.rb_node;
while (node) {
rbnode = container_of(node, struct regcache_rbtree_node, node);
- regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+ &top_reg);
if (reg >= base_reg && reg <= top_reg) {
rbtree_ctx->cached_rbnode = rbnode;
return rbnode;
@@ -91,7 +94,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
return NULL;
}
-static int regcache_rbtree_insert(struct rb_root *root,
+static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
struct regcache_rbtree_node *rbnode)
{
struct rb_node **new, *parent;
@@ -105,7 +108,7 @@ static int regcache_rbtree_insert(struct rb_root *root,
rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
node);
/* base and top registers of the current rbnode */
- regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
+ regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
&top_reg_tmp);
/* base register of the rbnode to be added */
base_reg = rbnode->base_reg;
@@ -137,24 +140,31 @@ static int rbtree_show(struct seq_file *s, void *ignored)
unsigned int base, top;
int nodes = 0;
int registers = 0;
+ int this_registers, average;
- mutex_lock(&map->lock);
+ map->lock(map);
for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
- regcache_rbtree_get_base_top_reg(n, &base, &top);
- seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1);
+ regcache_rbtree_get_base_top_reg(map, n, &base, &top);
+ this_registers = ((top - base) / map->reg_stride) + 1;
+ seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
nodes++;
- registers += top - base + 1;
+ registers += this_registers;
}
+ if (nodes)
+ average = registers / nodes;
+ else
+ average = 0;
+
seq_printf(s, "%d nodes, %d registers, average %d registers\n",
- nodes, registers, registers / nodes);
+ nodes, registers, average);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return 0;
}
@@ -248,7 +258,7 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
- reg_tmp = reg - rbnode->base_reg;
+ reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
*value = regcache_rbtree_get_register(rbnode, reg_tmp,
map->cache_word_size);
} else {
@@ -303,7 +313,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
*/
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
- reg_tmp = reg - rbnode->base_reg;
+ reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
val = regcache_rbtree_get_register(rbnode, reg_tmp,
map->cache_word_size);
if (val == value)
@@ -314,13 +324,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
/* look for an adjacent register to the one we are about to add */
for (node = rb_first(&rbtree_ctx->root); node;
node = rb_next(node)) {
- rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node);
+ rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
+ node);
for (i = 0; i < rbnode_tmp->blklen; i++) {
- reg_tmp = rbnode_tmp->base_reg + i;
- if (abs(reg_tmp - reg) != 1)
+ reg_tmp = rbnode_tmp->base_reg +
+ (i * map->reg_stride);
+ if (abs(reg_tmp - reg) != map->reg_stride)
continue;
/* decide where in the block to place our register */
- if (reg_tmp + 1 == reg)
+ if (reg_tmp + map->reg_stride == reg)
pos = i + 1;
else
pos = i;
@@ -350,14 +362,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return -ENOMEM;
}
regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
- regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
+ regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode;
}
return 0;
}
-static int regcache_rbtree_sync(struct regmap *map)
+static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
+ unsigned int max)
{
struct regcache_rbtree_ctx *rbtree_ctx;
struct rb_node *node;
@@ -365,19 +378,37 @@ static int regcache_rbtree_sync(struct regmap *map)
unsigned int regtmp;
unsigned int val;
int ret;
- int i;
+ int i, base, end;
rbtree_ctx = map->cache;
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
rbnode = rb_entry(node, struct regcache_rbtree_node, node);
- for (i = 0; i < rbnode->blklen; i++) {
- regtmp = rbnode->base_reg + i;
+
+ if (rbnode->base_reg < min)
+ continue;
+ if (rbnode->base_reg > max)
+ break;
+ if (rbnode->base_reg + rbnode->blklen < min)
+ continue;
+
+ if (min > rbnode->base_reg)
+ base = min - rbnode->base_reg;
+ else
+ base = 0;
+
+ if (max < rbnode->base_reg + rbnode->blklen)
+ end = rbnode->base_reg + rbnode->blklen - max;
+ else
+ end = rbnode->blklen;
+
+ for (i = base; i < end; i++) {
+ regtmp = rbnode->base_reg + (i * map->reg_stride);
val = regcache_rbtree_get_register(rbnode, i,
map->cache_word_size);
/* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, i);
- if (ret > 0 && val == map->reg_defaults[ret].def)
+ ret = regcache_lookup_reg(map, regtmp);
+ if (ret >= 0 && val == map->reg_defaults[ret].def)
continue;
map->cache_bypass = 1;
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 86cc342..bb9701d 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -57,7 +57,7 @@ static int regcache_hw_init(struct regmap *map)
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
val = regcache_get_val(map->reg_defaults_raw,
i, map->cache_word_size);
- if (regmap_volatile(map, i))
+ if (regmap_volatile(map, i * map->reg_stride))
continue;
count++;
}
@@ -74,9 +74,9 @@ static int regcache_hw_init(struct regmap *map)
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
val = regcache_get_val(map->reg_defaults_raw,
i, map->cache_word_size);
- if (regmap_volatile(map, i))
+ if (regmap_volatile(map, i * map->reg_stride))
continue;
- map->reg_defaults[j].reg = i;
+ map->reg_defaults[j].reg = i * map->reg_stride;
map->reg_defaults[j].def = val;
j++;
}
@@ -96,6 +96,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
int i;
void *tmp_buf;
+ for (i = 0; i < config->num_reg_defaults; i++)
+ if (config->reg_defaults[i].reg % map->reg_stride)
+ return -EINVAL;
+
if (map->cache_type == REGCACHE_NONE) {
map->cache_bypass = true;
return 0;
@@ -256,14 +260,13 @@ int regcache_write(struct regmap *map,
int regcache_sync(struct regmap *map)
{
int ret = 0;
- unsigned int val;
unsigned int i;
const char *name;
unsigned int bypass;
- BUG_ON(!map->cache_ops);
+ BUG_ON(!map->cache_ops || !map->cache_ops->sync);
- mutex_lock(&map->lock);
+ map->lock(map);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
dev_dbg(map->dev, "Syncing %s cache\n",
@@ -277,6 +280,10 @@ int regcache_sync(struct regmap *map)
/* Apply any patch first */
map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) {
+ if (map->patch[i].reg % map->reg_stride) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
@@ -286,35 +293,68 @@ int regcache_sync(struct regmap *map)
}
map->cache_bypass = 0;
- if (map->cache_ops->sync) {
- ret = map->cache_ops->sync(map);
- } else {
- for (i = 0; i < map->num_reg_defaults; i++) {
- ret = regcache_read(map, i, &val);
- if (ret < 0)
- goto out;
- map->cache_bypass = 1;
- ret = _regmap_write(map, i, val);
- map->cache_bypass = 0;
- if (ret < 0)
- goto out;
- dev_dbg(map->dev, "Synced register %#x, value %#x\n",
- map->reg_defaults[i].reg,
- map->reg_defaults[i].def);
- }
+ ret = map->cache_ops->sync(map, 0, map->max_register);
+
+ if (ret == 0)
+ map->cache_dirty = false;
- }
out:
trace_regcache_sync(map->dev, name, "stop");
/* Restore the bypass state */
map->cache_bypass = bypass;
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
EXPORT_SYMBOL_GPL(regcache_sync);
/**
+ * regcache_sync_region: Sync part of the register cache with the hardware.
+ *
+ * @map: map to sync.
+ * @min: first register to sync
+ * @max: last register to sync
+ *
+ * Write all non-default register values in the specified region to
+ * the hardware.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_sync_region(struct regmap *map, unsigned int min,
+ unsigned int max)
+{
+ int ret = 0;
+ const char *name;
+ unsigned int bypass;
+
+ BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+
+ map->lock(map);
+
+ /* Remember the initial bypass state */
+ bypass = map->cache_bypass;
+
+ name = map->cache_ops->name;
+ dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
+
+ trace_regcache_sync(map->dev, name, "start region");
+
+ if (!map->cache_dirty)
+ goto out;
+
+ ret = map->cache_ops->sync(map, min, max);
+
+out:
+ trace_regcache_sync(map->dev, name, "stop region");
+ /* Restore the bypass state */
+ map->cache_bypass = bypass;
+ map->unlock(map);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regcache_sync_region);
+
+/**
* regcache_cache_only: Put a register map into cache only mode
*
* @map: map to configure
@@ -328,10 +368,11 @@ EXPORT_SYMBOL_GPL(regcache_sync);
*/
void regcache_cache_only(struct regmap *map, bool enable)
{
- mutex_lock(&map->lock);
+ map->lock(map);
WARN_ON(map->cache_bypass && enable);
map->cache_only = enable;
- mutex_unlock(&map->lock);
+ trace_regmap_cache_only(map->dev, enable);
+ map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -346,9 +387,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only);
*/
void regcache_mark_dirty(struct regmap *map)
{
- mutex_lock(&map->lock);
+ map->lock(map);
map->cache_dirty = true;
- mutex_unlock(&map->lock);
+ map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
@@ -365,10 +406,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
*/
void regcache_cache_bypass(struct regmap *map, bool enable)
{
- mutex_lock(&map->lock);
+ map->lock(map);
WARN_ON(map->cache_only && enable);
map->cache_bypass = enable;
- mutex_unlock(&map->lock);
+ trace_regmap_cache_bypass(map->dev, enable);
+ map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -390,6 +432,13 @@ bool regcache_set_val(void *base, unsigned int idx,
cache[idx] = val;
break;
}
+ case 4: {
+ u32 *cache = base;
+ if (cache[idx] == val)
+ return true;
+ cache[idx] = val;
+ break;
+ }
default:
BUG();
}
@@ -411,6 +460,10 @@ unsigned int regcache_get_val(const void *base, unsigned int idx,
const u16 *cache = base;
return cache[idx];
}
+ case 4: {
+ const u32 *cache = base;
+ return cache[idx];
+ }
default:
BUG();
}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index b3b4b8f..3403803 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -11,7 +11,6 @@
*/
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
@@ -33,6 +32,35 @@ static int regmap_open_file(struct inode *inode, struct file *file)
return 0;
}
+static ssize_t regmap_name_read_file(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct regmap *map = file->private_data;
+ int ret;
+ char *buf;
+
+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
+ if (ret < 0) {
+ kfree(buf);
+ return ret;
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations regmap_name_fops = {
+ .open = regmap_open_file,
+ .read = regmap_name_read_file,
+ .llseek = default_llseek,
+};
+
static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -57,7 +85,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
val_len = 2 * map->format.val_bytes;
tot_len = reg_len + val_len + 3; /* : \n */
- for (i = 0; i < map->max_register + 1; i++) {
+ for (i = 0; i <= map->max_register; i += map->reg_stride) {
if (!regmap_readable(map, i))
continue;
@@ -103,9 +131,51 @@ out:
return ret;
}
+#undef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+/*
+ * This can be dangerous especially when we have clients such as
+ * PMICs, therefore don't provide any real compile time configuration option
+ * for this feature, people who want to use this will need to modify
+ * the source code directly.
+ */
+static ssize_t regmap_map_write_file(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ size_t buf_size;
+ char *start = buf;
+ unsigned long reg, value;
+ struct regmap *map = file->private_data;
+
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ while (*start == ' ')
+ start++;
+ reg = simple_strtoul(start, &start, 16);
+ while (*start == ' ')
+ start++;
+ if (strict_strtoul(start, 16, &value))
+ return -EINVAL;
+
+ /* Userspace has been fiddling around behind the kernel's back */
+ add_taint(TAINT_USER);
+
+ regmap_write(map, reg, value);
+ return buf_size;
+}
+#else
+#define regmap_map_write_file NULL
+#endif
+
static const struct file_operations regmap_map_fops = {
.open = regmap_open_file,
.read = regmap_map_read_file,
+ .write = regmap_map_write_file,
.llseek = default_llseek,
};
@@ -132,7 +202,7 @@ static ssize_t regmap_access_read_file(struct file *file,
reg_len = regmap_calc_reg_len(map->max_register, buf, count);
tot_len = reg_len + 10; /* ': R W V P\n' */
- for (i = 0; i < map->max_register + 1; i++) {
+ for (i = 0; i <= map->max_register; i += map->reg_stride) {
/* Ignore registers which are neither readable nor writable */
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
continue;
@@ -177,15 +247,25 @@ static const struct file_operations regmap_access_fops = {
.llseek = default_llseek,
};
-void regmap_debugfs_init(struct regmap *map)
+void regmap_debugfs_init(struct regmap *map, const char *name)
{
- map->debugfs = debugfs_create_dir(dev_name(map->dev),
- regmap_debugfs_root);
+ if (name) {
+ map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
+ dev_name(map->dev), name);
+ name = map->debugfs_name;
+ } else {
+ name = dev_name(map->dev);
+ }
+
+ map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
if (!map->debugfs) {
dev_warn(map->dev, "Failed to create debugfs directory\n");
return;
}
+ debugfs_create_file("name", 0400, map->debugfs,
+ map, &regmap_name_fops);
+
if (map->max_register) {
debugfs_create_file("registers", 0400, map->debugfs,
map, &regmap_map_fops);
@@ -206,6 +286,7 @@ void regmap_debugfs_init(struct regmap *map)
void regmap_debugfs_exit(struct regmap *map)
{
debugfs_remove_recursive(map->debugfs);
+ kfree(map->debugfs_name);
}
void regmap_debugfs_initcall(void)
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 9a3a8c5..5f6b247 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -15,8 +15,9 @@
#include <linux/module.h>
#include <linux/init.h>
-static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
+static int regmap_i2c_write(void *context, const void *data, size_t count)
{
+ struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;
@@ -29,10 +30,11 @@ static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
return -EIO;
}
-static int regmap_i2c_gather_write(struct device *dev,
+static int regmap_i2c_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
+ struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;
@@ -62,10 +64,11 @@ static int regmap_i2c_gather_write(struct device *dev,
return -EIO;
}
-static int regmap_i2c_read(struct device *dev,
+static int regmap_i2c_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
+ struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;
@@ -107,7 +110,7 @@ static struct regmap_bus regmap_i2c = {
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
- return regmap_init(&i2c->dev, &regmap_i2c, config);
+ return regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_i2c);
@@ -124,7 +127,7 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
- return devm_regmap_init(&i2c->dev, &regmap_i2c, config);
+ return devm_regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 428836f..cc7b4f7 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -49,6 +49,7 @@ static void regmap_irq_lock(struct irq_data *data)
static void regmap_irq_sync_unlock(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+ struct regmap *map = d->map;
int i, ret;
/*
@@ -57,11 +58,12 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
* suppress pointless writes.
*/
for (i = 0; i < d->chip->num_regs; i++) {
- ret = regmap_update_bits(d->map, d->chip->mask_base + i,
+ ret = regmap_update_bits(d->map, d->chip->mask_base +
+ (i * map->reg_stride),
d->mask_buf_def[i], d->mask_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
- d->chip->mask_base + i);
+ d->chip->mask_base + (i * map->reg_stride));
}
mutex_unlock(&d->lock);
@@ -70,17 +72,19 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
static void regmap_irq_enable(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+ struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
- d->mask_buf[irq_data->reg_offset] &= ~irq_data->mask;
+ d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
}
static void regmap_irq_disable(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+ struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
- d->mask_buf[irq_data->reg_offset] |= irq_data->mask;
+ d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
}
static struct irq_chip regmap_irq_chip = {
@@ -135,17 +139,19 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
data->status_buf[i] &= ~data->mask_buf[i];
if (data->status_buf[i] && chip->ack_base) {
- ret = regmap_write(map, chip->ack_base + i,
+ ret = regmap_write(map, chip->ack_base +
+ (i * map->reg_stride),
data->status_buf[i]);
if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
- chip->ack_base + i, ret);
+ chip->ack_base + (i * map->reg_stride),
+ ret);
}
}
for (i = 0; i < chip->num_irqs; i++) {
- if (data->status_buf[chip->irqs[i].reg_offset] &
- chip->irqs[i].mask) {
+ if (data->status_buf[chip->irqs[i].reg_offset /
+ map->reg_stride] & chip->irqs[i].mask) {
handle_nested_irq(data->irq_base + i);
handled = true;
}
@@ -180,6 +186,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
int cur_irq, i;
int ret = -ENOMEM;
+ for (i = 0; i < chip->num_irqs; i++) {
+ if (chip->irqs[i].reg_offset % map->reg_stride)
+ return -EINVAL;
+ if (chip->irqs[i].reg_offset / map->reg_stride >=
+ chip->num_regs)
+ return -EINVAL;
+ }
+
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
if (irq_base < 0) {
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
@@ -217,16 +231,17 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
mutex_init(&d->lock);
for (i = 0; i < chip->num_irqs; i++)
- d->mask_buf_def[chip->irqs[i].reg_offset]
+ d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
|= chip->irqs[i].mask;
/* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
- ret = regmap_write(map, chip->mask_base + i, d->mask_buf[i]);
+ ret = regmap_write(map, chip->mask_base + (i * map->reg_stride),
+ d->mask_buf[i]);
if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
- chip->mask_base + i, ret);
+ chip->mask_base + (i * map->reg_stride), ret);
goto err_alloc;
}
}
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
new file mode 100644
index 00000000..febd6de
--- /dev/null
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -0,0 +1,224 @@
+/*
+ * Register map access API - MMIO support
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct regmap_mmio_context {
+ void __iomem *regs;
+ unsigned val_bytes;
+};
+
+static int regmap_mmio_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ struct regmap_mmio_context *ctx = context;
+ u32 offset;
+
+ BUG_ON(reg_size != 4);
+
+ offset = be32_to_cpup(reg);
+
+ while (val_size) {
+ switch (ctx->val_bytes) {
+ case 1:
+ writeb(*(u8 *)val, ctx->regs + offset);
+ break;
+ case 2:
+ writew(be16_to_cpup(val), ctx->regs + offset);
+ break;
+ case 4:
+ writel(be32_to_cpup(val), ctx->regs + offset);
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ writeq(be64_to_cpup(val), ctx->regs + offset);
+ break;
+#endif
+ default:
+ /* Should be caught by regmap_mmio_check_config */
+ BUG();
+ }
+ val_size -= ctx->val_bytes;
+ val += ctx->val_bytes;
+ offset += ctx->val_bytes;
+ }
+
+ return 0;
+}
+
+static int regmap_mmio_write(void *context, const void *data, size_t count)
+{
+ BUG_ON(count < 4);
+
+ return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
+}
+
+static int regmap_mmio_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct regmap_mmio_context *ctx = context;
+ u32 offset;
+
+ BUG_ON(reg_size != 4);
+
+ offset = be32_to_cpup(reg);
+
+ while (val_size) {
+ switch (ctx->val_bytes) {
+ case 1:
+ *(u8 *)val = readb(ctx->regs + offset);
+ break;
+ case 2:
+ *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
+ break;
+ case 4:
+ *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
+ break;
+#endif
+ default:
+ /* Should be caught by regmap_mmio_check_config */
+ BUG();
+ }
+ val_size -= ctx->val_bytes;
+ val += ctx->val_bytes;
+ offset += ctx->val_bytes;
+ }
+
+ return 0;
+}
+
+static void regmap_mmio_free_context(void *context)
+{
+ kfree(context);
+}
+
+static struct regmap_bus regmap_mmio = {
+ .fast_io = true,
+ .write = regmap_mmio_write,
+ .gather_write = regmap_mmio_gather_write,
+ .read = regmap_mmio_read,
+ .free_context = regmap_mmio_free_context,
+};
+
+struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+ const struct regmap_config *config)
+{
+ struct regmap_mmio_context *ctx;
+ int min_stride;
+
+ if (config->reg_bits != 32)
+ return ERR_PTR(-EINVAL);
+
+ if (config->pad_bits)
+ return ERR_PTR(-EINVAL);
+
+ switch (config->val_bits) {
+ case 8:
+ /* The core treats 0 as 1 */
+ min_stride = 0;
+ break;
+ case 16:
+ min_stride = 2;
+ break;
+ case 32:
+ min_stride = 4;
+ break;
+#ifdef CONFIG_64BIT
+ case 64:
+ min_stride = 8;
+ break;
+#endif
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (config->reg_stride < min_stride)
+ return ERR_PTR(-EINVAL);
+
+ ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->regs = regs;
+ ctx->val_bytes = config->val_bits / 8;
+
+ return ctx;
+}
+
+/**
+ * regmap_init_mmio(): Initialise register map
+ *
+ * @dev: Device that will be interacted with
+ * @regs: Pointer to memory-mapped IO region
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_mmio(struct device *dev,
+ void __iomem *regs,
+ const struct regmap_config *config)
+{
+ struct regmap_mmio_context *ctx;
+
+ ctx = regmap_mmio_gen_context(regs, config);
+ if (IS_ERR(ctx))
+ return ERR_CAST(ctx);
+
+ return regmap_init(dev, &regmap_mmio, ctx, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_mmio);
+
+/**
+ * devm_regmap_init_mmio(): Initialise managed register map
+ *
+ * @dev: Device that will be interacted with
+ * @regs: Pointer to memory-mapped IO region
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_mmio(struct device *dev,
+ void __iomem *regs,
+ const struct regmap_config *config)
+{
+ struct regmap_mmio_context *ctx;
+
+ ctx = regmap_mmio_gen_context(regs, config);
+ if (IS_ERR(ctx))
+ return ERR_CAST(ctx);
+
+ return devm_regmap_init(dev, &regmap_mmio, ctx, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 7c0c35a..ffa46a9 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -15,17 +15,19 @@
#include <linux/init.h>
#include <linux/module.h>
-static int regmap_spi_write(struct device *dev, const void *data, size_t count)
+static int regmap_spi_write(void *context, const void *data, size_t count)
{
+ struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write(spi, data, count);
}
-static int regmap_spi_gather_write(struct device *dev,
+static int regmap_spi_gather_write(void *context,
const void *reg, size_t reg_len,
const void *val, size_t val_len)
{
+ struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
struct spi_message m;
struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, },
@@ -38,10 +40,11 @@ static int regmap_spi_gather_write(struct device *dev,
return spi_sync(spi, &m);
}
-static int regmap_spi_read(struct device *dev,
+static int regmap_spi_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
+ struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write_then_read(spi, reg, reg_size, val, val_size);
@@ -66,7 +69,7 @@ static struct regmap_bus regmap_spi = {
struct regmap *regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
- return regmap_init(&spi->dev, &regmap_spi, config);
+ return regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_spi);
@@ -83,7 +86,7 @@ EXPORT_SYMBOL_GPL(regmap_init_spi);
struct regmap *devm_regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
- return devm_regmap_init(&spi->dev, &regmap_spi, config);
+ return devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index a239ce8..1eb6de3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -10,8 +10,9 @@
* published by the Free Software Foundation.
*/
+#include <linux/device.h>
#include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/err.h>
@@ -111,18 +112,36 @@ static void regmap_format_10_14_write(struct regmap *map,
out[0] = reg >> 2;
}
-static void regmap_format_8(void *buf, unsigned int val)
+static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
- b[0] = val;
+ b[0] = val << shift;
}
-static void regmap_format_16(void *buf, unsigned int val)
+static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
{
__be16 *b = buf;
- b[0] = cpu_to_be16(val);
+ b[0] = cpu_to_be16(val << shift);
+}
+
+static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
+{
+ u8 *b = buf;
+
+ val <<= shift;
+
+ b[0] = val >> 16;
+ b[1] = val >> 8;
+ b[2] = val;
+}
+
+static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
+{
+ __be32 *b = buf;
+
+ b[0] = cpu_to_be32(val << shift);
}
static unsigned int regmap_parse_8(void *buf)
@@ -141,11 +160,51 @@ static unsigned int regmap_parse_16(void *buf)
return b[0];
}
+static unsigned int regmap_parse_24(void *buf)
+{
+ u8 *b = buf;
+ unsigned int ret = b[2];
+ ret |= ((unsigned int)b[1]) << 8;
+ ret |= ((unsigned int)b[0]) << 16;
+
+ return ret;
+}
+
+static unsigned int regmap_parse_32(void *buf)
+{
+ __be32 *b = buf;
+
+ b[0] = be32_to_cpu(b[0]);
+
+ return b[0];
+}
+
+static void regmap_lock_mutex(struct regmap *map)
+{
+ mutex_lock(&map->mutex);
+}
+
+static void regmap_unlock_mutex(struct regmap *map)
+{
+ mutex_unlock(&map->mutex);
+}
+
+static void regmap_lock_spinlock(struct regmap *map)
+{
+ spin_lock(&map->spinlock);
+}
+
+static void regmap_unlock_spinlock(struct regmap *map)
+{
+ spin_unlock(&map->spinlock);
+}
+
/**
* regmap_init(): Initialise register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
+ * @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
@@ -154,6 +213,7 @@ static unsigned int regmap_parse_16(void *buf)
*/
struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus,
+ void *bus_context,
const struct regmap_config *config)
{
struct regmap *map;
@@ -168,14 +228,28 @@ struct regmap *regmap_init(struct device *dev,
goto err;
}
- mutex_init(&map->lock);
+ if (bus->fast_io) {
+ spin_lock_init(&map->spinlock);
+ map->lock = regmap_lock_spinlock;
+ map->unlock = regmap_unlock_spinlock;
+ } else {
+ mutex_init(&map->mutex);
+ map->lock = regmap_lock_mutex;
+ map->unlock = regmap_unlock_mutex;
+ }
map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8);
map->format.pad_bytes = config->pad_bits / 8;
map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8);
map->format.buf_size += map->format.pad_bytes;
+ map->reg_shift = config->pad_bits % 8;
+ if (config->reg_stride)
+ map->reg_stride = config->reg_stride;
+ else
+ map->reg_stride = 1;
map->dev = dev;
map->bus = bus;
+ map->bus_context = bus_context;
map->max_register = config->max_register;
map->writeable_reg = config->writeable_reg;
map->readable_reg = config->readable_reg;
@@ -190,7 +264,7 @@ struct regmap *regmap_init(struct device *dev,
map->read_flag_mask = bus->read_flag_mask;
}
- switch (config->reg_bits) {
+ switch (config->reg_bits + map->reg_shift) {
case 2:
switch (config->val_bits) {
case 6:
@@ -239,6 +313,10 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_reg = regmap_format_16;
break;
+ case 32:
+ map->format.format_reg = regmap_format_32;
+ break;
+
default:
goto err_map;
}
@@ -252,6 +330,14 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_val = regmap_format_16;
map->format.parse_val = regmap_parse_16;
break;
+ case 24:
+ map->format.format_val = regmap_format_24;
+ map->format.parse_val = regmap_parse_24;
+ break;
+ case 32:
+ map->format.format_val = regmap_format_32;
+ map->format.parse_val = regmap_parse_32;
+ break;
}
if (!map->format.format_write &&
@@ -264,7 +350,7 @@ struct regmap *regmap_init(struct device *dev,
goto err_map;
}
- regmap_debugfs_init(map);
+ regmap_debugfs_init(map, config->name);
ret = regcache_init(map, config);
if (ret < 0)
@@ -291,6 +377,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
+ * @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
@@ -300,6 +387,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*/
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
+ void *bus_context,
const struct regmap_config *config)
{
struct regmap **ptr, *regmap;
@@ -308,7 +396,7 @@ struct regmap *devm_regmap_init(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- regmap = regmap_init(dev, bus, config);
+ regmap = regmap_init(dev, bus, bus_context, config);
if (!IS_ERR(regmap)) {
*ptr = regmap;
devres_add(dev, ptr);
@@ -335,7 +423,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
{
int ret;
- mutex_lock(&map->lock);
+ map->lock(map);
regcache_exit(map);
regmap_debugfs_exit(map);
@@ -347,13 +435,14 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type;
+ regmap_debugfs_init(map, config->name);
+
map->cache_bypass = false;
map->cache_only = false;
- regmap_debugfs_init(map);
ret = regcache_init(map, config);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -365,6 +454,8 @@ void regmap_exit(struct regmap *map)
{
regcache_exit(map);
regmap_debugfs_exit(map);
+ if (map->bus->free_context)
+ map->bus->free_context(map->bus_context);
kfree(map->work_buf);
kfree(map);
}
@@ -382,7 +473,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
/* Check for unwritable registers before we start */
if (map->writeable_reg)
for (i = 0; i < val_len / map->format.val_bytes; i++)
- if (!map->writeable_reg(map->dev, reg + i))
+ if (!map->writeable_reg(map->dev,
+ reg + (i * map->reg_stride)))
return -EINVAL;
if (!map->cache_bypass && map->format.parse_val) {
@@ -391,7 +483,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
for (i = 0; i < val_len / val_bytes; i++) {
memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
ival = map->format.parse_val(map->work_buf);
- ret = regcache_write(map, reg + i, ival);
+ ret = regcache_write(map, reg + (i * map->reg_stride),
+ ival);
if (ret) {
dev_err(map->dev,
"Error in caching of register: %u ret: %d\n",
@@ -405,7 +498,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
}
}
- map->format.format_reg(map->work_buf, reg);
+ map->format.format_reg(map->work_buf, reg, map->reg_shift);
u8[0] |= map->write_flag_mask;
@@ -418,12 +511,12 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
*/
if (val == (map->work_buf + map->format.pad_bytes +
map->format.reg_bytes))
- ret = map->bus->write(map->dev, map->work_buf,
+ ret = map->bus->write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes +
val_len);
else if (map->bus->gather_write)
- ret = map->bus->gather_write(map->dev, map->work_buf,
+ ret = map->bus->gather_write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes,
val, val_len);
@@ -438,7 +531,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
memcpy(buf, map->work_buf, map->format.reg_bytes);
memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
- ret = map->bus->write(map->dev, buf, len);
+ ret = map->bus->write(map->bus_context, buf, len);
kfree(buf);
}
@@ -472,7 +565,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_hw_write_start(map->dev, reg, 1);
- ret = map->bus->write(map->dev, map->work_buf,
+ ret = map->bus->write(map->bus_context, map->work_buf,
map->format.buf_size);
trace_regmap_hw_write_done(map->dev, reg, 1);
@@ -480,7 +573,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
return ret;
} else {
map->format.format_val(map->work_buf + map->format.reg_bytes
- + map->format.pad_bytes, val);
+ + map->format.pad_bytes, val, 0);
return _regmap_raw_write(map, reg,
map->work_buf +
map->format.reg_bytes +
@@ -503,11 +596,14 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
int ret;
- mutex_lock(&map->lock);
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
ret = _regmap_write(map, reg, val);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -534,11 +630,16 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int ret;
- mutex_lock(&map->lock);
+ if (val_len % map->format.val_bytes)
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
ret = _regmap_raw_write(map, reg, val, val_len);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -567,8 +668,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (!map->format.parse_val)
return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
- mutex_lock(&map->lock);
+ map->lock(map);
/* No formatting is require if val_byte is 1 */
if (val_bytes == 1) {
@@ -589,7 +692,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
kfree(wval);
out:
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
@@ -600,7 +703,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8 *u8 = map->work_buf;
int ret;
- map->format.format_reg(map->work_buf, reg);
+ map->format.format_reg(map->work_buf, reg, map->reg_shift);
/*
* Some buses or devices flag reads by setting the high bits in the
@@ -613,7 +716,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
trace_regmap_hw_read_start(map->dev, reg,
val_len / map->format.val_bytes);
- ret = map->bus->read(map->dev, map->work_buf,
+ ret = map->bus->read(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
@@ -663,11 +766,14 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
int ret;
- mutex_lock(&map->lock);
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
ret = _regmap_read(map, reg, val);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -687,17 +793,39 @@ EXPORT_SYMBOL_GPL(regmap_read);
int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
size_t val_len)
{
- size_t val_count = val_len / map->format.val_bytes;
- int ret;
+ size_t val_bytes = map->format.val_bytes;
+ size_t val_count = val_len / val_bytes;
+ unsigned int v;
+ int ret, i;
- WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
- map->cache_type != REGCACHE_NONE);
+ if (val_len % map->format.val_bytes)
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
- mutex_lock(&map->lock);
+ map->lock(map);
- ret = _regmap_raw_read(map, reg, val, val_len);
+ if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
+ map->cache_type == REGCACHE_NONE) {
+ /* Physical block read if there's no cache involved */
+ ret = _regmap_raw_read(map, reg, val, val_len);
- mutex_unlock(&map->lock);
+ } else {
+ /* Otherwise go word by word for the cache; should be low
+ * cost as we expect to hit the cache.
+ */
+ for (i = 0; i < val_count; i++) {
+ ret = _regmap_read(map, reg + (i * map->reg_stride),
+ &v);
+ if (ret != 0)
+ goto out;
+
+ map->format.format_val(val + (i * val_bytes), v, 0);
+ }
+ }
+
+ out:
+ map->unlock(map);
return ret;
}
@@ -723,6 +851,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
if (!map->format.parse_val)
return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
if (vol || map->cache_type == REGCACHE_NONE) {
ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
@@ -733,7 +863,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
map->format.parse_val(val + i);
} else {
for (i = 0; i < val_count; i++) {
- ret = regmap_read(map, reg + i, val + (i * val_bytes));
+ ret = regmap_read(map, reg + (i * map->reg_stride),
+ val + (i * val_bytes));
if (ret != 0)
return ret;
}
@@ -750,7 +881,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
int ret;
unsigned int tmp, orig;
- mutex_lock(&map->lock);
+ map->lock(map);
ret = _regmap_read(map, reg, &orig);
if (ret != 0)
@@ -767,7 +898,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
}
out:
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -807,7 +938,7 @@ int regmap_update_bits_lazy(struct regmap *map, unsigned int reg,
int ret, new;
unsigned int tmp;
- mutex_lock(&map->lock);
+ map->lock(map);
ret = _regmap_read(map, reg, &tmp);
if (ret != 0)
@@ -820,7 +951,7 @@ int regmap_update_bits_lazy(struct regmap *map, unsigned int reg,
}
out:
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -869,7 +1000,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
if (map->patch)
return -EBUSY;
- mutex_lock(&map->lock);
+ map->lock(map);
bypass = map->cache_bypass;
@@ -897,12 +1028,27 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
out:
map->cache_bypass = bypass;
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_register_patch);
+/**
+ * regmap_get_val_bytes(): Report the size of a register value
+ *
+ * Report the size of a register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_val_bytes(struct regmap *map)
+{
+ if (map->format.format_write)
+ return -EINVAL;
+
+ return map->format.val_bytes;
+}
+EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+
static int __init regmap_initcall(void)
{
regmap_debugfs_initcall();
diff --git a/drivers/bluetooth/ti_bluesleep.c b/drivers/bluetooth/ti_bluesleep.c
index d86fd26..2ab5324 100644
--- a/drivers/bluetooth/ti_bluesleep.c
+++ b/drivers/bluetooth/ti_bluesleep.c
@@ -31,37 +31,17 @@
*/
#include <linux/module.h> /* kernel module definitions */
-#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/uaccess.h>
-#include <linux/version.h>
-#include <linux/workqueue.h>
#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/ioport.h>
-#include <linux/param.h>
-#include <linux/bitops.h>
-#include <linux/termios.h>
-#include <linux/wakelock.h>
#include <mach/gpio.h>
-#include <linux/serial_core.h>
-#include <linux/tegra_uart.h>
#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h> /* event notifications */
-#include "hci_uart.h"
/*
* Defines
*/
-
#define VERSION "1.1"
#define POLARITY_LOW 0
@@ -70,9 +50,7 @@
struct bluesleep_info {
unsigned host_wake_irq;
struct uart_port *uport;
- struct wake_lock wake_lock;
int irq_polarity;
- int has_ext_wake;
};
@@ -81,16 +59,6 @@ struct bluesleep_info {
#define BT_ACTIVE 0x02
#define BT_SUSPEND 0x04
-
-/* work function */
-static void hostwake_sleep_work(struct work_struct *work);
-
-/* work queue */
-DECLARE_DELAYED_WORK(ti_sleep_workqueue, hostwake_sleep_work);
-
-/* Macros for handling sleep work */
-#define hostwake_workqueue() schedule_delayed_work(&ti_sleep_workqueue, 0)
-
static struct bluesleep_info *bsi;
/* module usage */
@@ -102,66 +70,6 @@ static atomic_t open_count = ATOMIC_INIT(1);
/** Global state flags */
static unsigned long flags;
-/** Tasklet to respond to change in hostwake line */
-static struct tasklet_struct hostwake_task;
-
-/** Lock for state transitions */
-static spinlock_t rw_lock;
-
-/*
- * Local functions
- */
-static void hsuart_power(int on)
-{
- pr_debug("%s", __func__);
-
- if (on) {
- tegra_uart_request_clock_on(bsi->uport);
- tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
- } else {
- tegra_uart_set_mctrl(bsi->uport, 0);
- tegra_uart_request_clock_off(bsi->uport);
- }
-}
-
-
-
-/**
- * @brief@ main sleep work handling function which update the flags
- * and activate and deactivate UART .
- */
-
-static void hostwake_sleep_work(struct work_struct *work)
-{
- pr_debug("%s", __func__);
- free_irq(bsi->host_wake_irq, "tibluesleep");
- /*Activating UART */
- if (test_bit(BT_SUSPEND, &flags)) {
- BT_DBG("Activate UART");
- hsuart_power(1);
-
- }
- bsi->has_ext_wake = 0;
- clear_bit(BT_SUSPEND, &flags);
- set_bit(BT_ACTIVE, &flags);
-
-}
-
-
-/**
- * A tasklet function that runs in tasklet context
- * @param data Not used.
- */
-static void bluesleep_hostwake_task(unsigned long data)
-{
- pr_debug("%s", __func__);
- disable_irq(bsi->host_wake_irq);
- spin_lock(&rw_lock);
- hostwake_workqueue();
- spin_unlock(&rw_lock);
-}
-
-
/**
* Schedules a tasklet to run when receiving an interrupt on the
* <code>HOST_WAKE</code> GPIO pin.
@@ -170,11 +78,8 @@ static void bluesleep_hostwake_task(unsigned long data)
*/
static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
{
-
pr_debug("%s", __func__);
- /* schedule a tasklet to handle the change in the host wake line */
- bsi->has_ext_wake = 1;
- tasklet_schedule(&hostwake_task);
+ disable_irq_nosync(bsi->host_wake_irq);
return IRQ_HANDLED;
}
@@ -183,8 +88,7 @@ static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
* @return On success, 0. On error, -1, and <code>errno</code> is set
* appropriately.
*/
-
- int bluesleep_start(struct uart_port *uport)
+int bluesleep_start(struct uart_port *uport)
{
int retval;
bsi->uport = uport;
@@ -224,9 +128,8 @@ fail:
/**
* Stops the Sleep-Mode Protocol on the Host.
*/
- void bluesleep_stop(void)
+void bluesleep_stop(void)
{
-
pr_debug("%s", __func__);
if (disable_irq_wake(bsi->host_wake_irq))
@@ -264,7 +167,6 @@ static int bluesleep_probe(struct platform_device *pdev)
else
bsi->irq_polarity = POLARITY_HIGH;/*anything else*/
- wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep");
clear_bit(BT_SUSPEND, &flags);
set_bit(BT_ACTIVE, &flags);
@@ -282,17 +184,11 @@ static int bluesleep_remove(struct platform_device *pdev)
return 0;
}
-
static int bluesleep_resume(struct platform_device *pdev)
{
-
pr_debug("%s", __func__);
if (test_bit(BT_SUSPEND, &flags)) {
-
- if ((bsi->uport != NULL) && (bsi->has_ext_wake)) {
- tegra_uart_request_clock_on(bsi->uport);
- tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
- }
+ free_irq(bsi->host_wake_irq, "tibluesleep");
clear_bit(BT_SUSPEND, &flags);
set_bit(BT_ACTIVE, &flags);
}
@@ -317,6 +213,7 @@ static struct platform_driver bluesleep_driver = {
.owner = THIS_MODULE,
},
};
+
/**
* Initializes the module.
* @return On success, 0. On error, -1, and <code>errno</code> is set
@@ -337,12 +234,6 @@ static int __init bluesleep_init(void)
flags = FLAG_RESET; /* clear all status bits */
- /* Initialize spinlock. */
- spin_lock_init(&rw_lock);
-
- /* initialize host wake tasklet */
- tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
-
return 0;
fail:
return retval;
@@ -351,7 +242,6 @@ fail:
/**
* Cleans up the module.
*/
-
static void __exit bluesleep_exit(void)
{
if (bsi == NULL)
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 6db161f..a9a1137 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -89,6 +89,51 @@ void clk_put(struct clk *clk)
}
EXPORT_SYMBOL(clk_put);
+static void devm_clk_release(struct device *dev, void *res)
+{
+ clk_put(*(struct clk **)res);
+}
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+ struct clk **ptr, *clk;
+
+ ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ clk = clk_get(dev, id);
+ if (!IS_ERR(clk)) {
+ *ptr = clk;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return clk;
+}
+EXPORT_SYMBOL(devm_clk_get);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+ struct clk **c = res;
+ if (!c || !*c) {
+ WARN_ON(!c || !*c);
+ return 0;
+ }
+ return *c == data;
+}
+
+void devm_clk_put(struct device *dev, struct clk *clk)
+{
+ int ret;
+
+ ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk);
+
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_clk_put);
+
void clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 3acc428..629806d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1640,9 +1640,9 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
unsigned int pmax = policy->max;
qmin = min((unsigned int)pm_qos_request(PM_QOS_CPU_FREQ_MIN),
- data->max);
+ data->user_policy.max);
qmax = max((unsigned int)pm_qos_request(PM_QOS_CPU_FREQ_MAX),
- data->min);
+ data->user_policy.min);
pr_debug("setting new policy for CPU %u: %u - %u (%u - %u) kHz\n",
policy->cpu, pmin, pmax, qmin, qmax);
@@ -1654,7 +1654,8 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
memcpy(&policy->cpuinfo, &data->cpuinfo,
sizeof(struct cpufreq_cpuinfo));
- if (policy->min > data->max || policy->max < data->min) {
+ if (policy->min > data->user_policy.max ||
+ policy->max < data->user_policy.min) {
ret = -EINVAL;
goto error_out;
}
@@ -1785,6 +1786,56 @@ no_policy:
}
EXPORT_SYMBOL(cpufreq_update_policy);
+/*
+ * cpufreq_set_gov - set governor for a cpu
+ * @cpu: CPU whose governor needs to be changed
+ * @target_gov: new governor to be set
+ */
+int cpufreq_set_gov(char *target_gov, unsigned int cpu)
+{
+ int ret = 0;
+ struct cpufreq_policy new_policy;
+ struct cpufreq_policy *cur_policy;
+
+ if (target_gov == NULL)
+ return -EINVAL;
+
+ /* Get current governer */
+ cur_policy = cpufreq_cpu_get(cpu);
+ if (!cur_policy)
+ return -EINVAL;
+
+ new_policy = *cur_policy;
+ if (!strncmp(cur_policy->governor->name, target_gov,
+ strlen(target_gov))) {
+ /* Target governer & current governer is same */
+ ret = -EINVAL;
+ goto err_out;
+ } else {
+ if (cpufreq_parse_governor(target_gov, &new_policy.policy,
+ &new_policy.governor)) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (lock_policy_rwsem_write(cur_policy->cpu) < 0) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ ret = __cpufreq_set_policy(cur_policy, &new_policy);
+
+ cur_policy->user_policy.policy = cur_policy->policy;
+ cur_policy->user_policy.governor = cur_policy->governor;
+
+ unlock_policy_rwsem_write(cur_policy->cpu);
+ }
+err_out:
+ cpufreq_cpu_put(cur_policy);
+ return ret;
+}
+EXPORT_SYMBOL(cpufreq_set_gov);
+
static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
index 22a96ed..291cb4b 100644
--- a/drivers/crypto/tegra-aes.c
+++ b/drivers/crypto/tegra-aes.c
@@ -890,15 +890,18 @@ static int tegra_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
spin_lock_irqsave(&dd->lock, flags);
err = ablkcipher_enqueue_request(&dd->queue, req);
- bsev_busy = test_and_set_bit(FLAGS_BUSY, &dd->bsev.busy);
- bsea_busy = test_and_set_bit(FLAGS_BUSY, &dd->bsea.busy);
spin_unlock_irqrestore(&dd->lock, flags);
-
- if (!bsev_busy)
+ bsev_busy = test_and_set_bit(FLAGS_BUSY, &dd->bsev.busy);
+ if (!bsev_busy) {
queue_work(bsev_wq, &bsev_work);
+ goto finish;
+ }
+
+ bsea_busy = test_and_set_bit(FLAGS_BUSY, &dd->bsea.busy);
if (!bsea_busy)
queue_work(bsea_wq, &bsea_work);
+finish:
return err;
}
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 3a0893f..17e9c1c 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -191,6 +191,7 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -199,6 +200,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
{
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -213,8 +215,20 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return TEGRA_GPIO_TO_IRQ(offset);
}
+static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return 0;
+}
+
+static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ tegra_gpio_disable(offset);
+}
+
static struct gpio_chip tegra_gpio_chip = {
.label = "tegra-gpio",
+ .request = tegra_gpio_request,
+ .free = tegra_gpio_free,
.direction_input = tegra_gpio_direction_input,
.get = tegra_gpio_get,
.direction_output = tegra_gpio_direction_output,
diff --git a/drivers/gpu/ion/tegra/tegra_ion.c b/drivers/gpu/ion/tegra/tegra_ion.c
index 2252079..e929ec8 100644
--- a/drivers/gpu/ion/tegra/tegra_ion.c
+++ b/drivers/gpu/ion/tegra/tegra_ion.c
@@ -31,7 +31,7 @@
#define HEAP_FLAGS 0xFF
#if !defined(CONFIG_TEGRA_NVMAP)
-#include "mach/nvmap.h"
+#include "linux/nvmap.h"
struct nvmap_device *nvmap_dev;
#endif
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 5cd25bd..81c054e 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -155,6 +155,26 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
}
+static void sixaxis_set_led_bt(struct hid_device *hdev)
+{
+ hid_info(hdev, "set LED BT\n");
+ /* set first LED on BT connection */
+ unsigned char led_data[] = {
+ 0x01,
+ /* rumble values */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* LED settings 0x02=LED1 .. 0x10=LED4 */
+ 0x02,
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 4 */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 3 */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 2 */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ hdev->hid_output_raw_report(hdev, led_data, sizeof(led_data),
+ HID_OUTPUT_REPORT);
+}
+
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -187,8 +207,11 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
ret = sixaxis_set_operational_usb(hdev);
}
- else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+ else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
ret = sixaxis_set_operational_bt(hdev);
+ if (ret >= 0)
+ sixaxis_set_led_bt(hdev);
+ }
else
ret = 0;
diff --git a/drivers/hwmon/tegra-tsensor.c b/drivers/hwmon/tegra-tsensor.c
index b466033..28597ef 100644
--- a/drivers/hwmon/tegra-tsensor.c
+++ b/drivers/hwmon/tegra-tsensor.c
@@ -38,7 +38,7 @@
/* macro to enable tsensor hw reset */
/* FIXME: till tsensor temperature is reliable this should be 0 */
-#define ENABLE_TSENSOR_HW_RESET 0
+#define ENABLE_TSENSOR_HW_RESET 1
/* tsensor instance used for temperature calculation */
#define TSENSOR_FUSE_REV1 8
@@ -1542,7 +1542,7 @@ static int tsensor_within_limits(struct tegra_tsensor_data *data)
static void tsensor_work_func(struct work_struct *work)
{
- struct tegra_tsensor_data *data = container_of(work,
+ struct tegra_tsensor_data *data = container_of(to_delayed_work(work),
struct tegra_tsensor_data, work);
if (!data->alert_func)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index a4c1e0d..96916be 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -106,13 +106,26 @@
#define I2C_HEADER_10BIT_ADDR (1<<18)
#define I2C_HEADER_IE_ENABLE (1<<17)
#define I2C_HEADER_REPEAT_START (1<<16)
+#define I2C_HEADER_CONTINUE_XFER (1<<15)
#define I2C_HEADER_MASTER_ADDR_SHIFT 12
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
#define SL_ADDR1(addr) (addr & 0xff)
#define SL_ADDR2(addr) ((addr >> 8) & 0xff)
+/*
+ * msg_end_type: The bus control which need to be send at end of transfer.
+ * @MSG_END_STOP: Send stop pulse at end of transfer.
+ * @MSG_END_REPEAT_START: Send repeat start at end of transfer.
+ * @MSG_END_CONTINUE: The following on message is coming and so do not send
+ * stop or repeat start.
+ */
+enum msg_end_type {
+ MSG_END_STOP,
+ MSG_END_REPEAT_START,
+ MSG_END_CONTINUE,
+};
struct tegra_i2c_dev;
@@ -570,9 +583,12 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
}
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ i2c_readl(i2c_dev, I2C_INT_STATUS);
- if (i2c_dev->is_dvc)
+ if (i2c_dev->is_dvc) {
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ dvc_readl(i2c_dev, DVC_STATUS);
+ }
if (status & I2C_INT_PACKET_XFER_COMPLETE) {
BUG_ON(i2c_dev->msg_buf_remaining);
@@ -608,20 +624,23 @@ err:
I2C_INT_RX_FIFO_DATA_REQ | I2C_INT_TX_FIFO_OVERFLOW);
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ i2c_readl(i2c_dev, I2C_INT_STATUS);
/* An error occured, mask dvc interrupt */
if (i2c_dev->is_dvc)
dvc_i2c_mask_irq(i2c_dev, DVC_CTRL_REG3_I2C_DONE_INTR_EN);
- if (i2c_dev->is_dvc)
+ if (i2c_dev->is_dvc) {
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ dvc_readl(i2c_dev, DVC_STATUS);
+ }
complete(&i2c_dev->msg_complete);
return IRQ_HANDLED;
}
static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
- struct i2c_msg *msg, int stop)
+ struct i2c_msg *msg, enum msg_end_type end_state)
{
struct tegra_i2c_dev *i2c_dev = i2c_bus->dev;
u32 int_mask;
@@ -654,8 +673,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
i2c_writel(i2c_dev, i2c_dev->payload_size, I2C_TX_FIFO);
i2c_dev->io_header = I2C_HEADER_IE_ENABLE;
- if (!stop)
+ if (end_state == MSG_END_CONTINUE)
+ i2c_dev->io_header |= I2C_HEADER_CONTINUE_XFER;
+ else if (end_state == MSG_END_REPEAT_START)
i2c_dev->io_header |= I2C_HEADER_REPEAT_START;
+
if (msg->flags & I2C_M_TEN) {
i2c_dev->io_header |= msg->addr;
i2c_dev->io_header |= I2C_HEADER_10BIT_ADDR;
@@ -772,8 +794,14 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
tegra_i2c_clock_enable(i2c_dev);
for (i = 0; i < num; i++) {
- int stop = (i == (num - 1)) ? 1 : 0;
- ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], stop);
+ enum msg_end_type end_type = MSG_END_STOP;
+ if (i < (num - 1)) {
+ if (msgs[i + 1].flags & I2C_M_NOSTART)
+ end_type = MSG_END_CONTINUE;
+ else
+ end_type = MSG_END_REPEAT_START;
+ }
+ ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], end_type);
if (ret)
break;
}
diff --git a/drivers/input/touchscreen/rmi4/rmi_bus.c b/drivers/input/touchscreen/rmi4/rmi_bus.c
index 6a269df..def8a20 100644
--- a/drivers/input/touchscreen/rmi4/rmi_bus.c
+++ b/drivers/input/touchscreen/rmi4/rmi_bus.c
@@ -39,17 +39,15 @@ static int rmi_bus_match(struct device *dev, struct device_driver *driver)
rmi_dev = to_rmi_device(dev);
pdata = to_rmi_platform_data(rmi_dev);
- pr_info(" rmi_driver->driver.name = %s\n", rmi_driver->driver.name);
- pr_info(" device:rmi_device = 0x%x \n", rmi_dev);
- pr_info(" device:rmi_device:rmi_device_platform_data:driver_name = %s \n", pdata->driver_name);
- pr_info(" rmi_device:driver = 0x%x \n", rmi_dev->driver);
+ pr_info("rmi_driver->driver.name = %s\n", rmi_driver->driver.name);
+ pr_info("device:rmi_device:rmi_device_platform_data:driver_name = %s\n",
+ pdata->driver_name);
if (!strcmp(pdata->driver_name, rmi_driver->driver.name)) {
rmi_dev->driver = rmi_driver;
- pr_info(" names match, so now rmi_device:driver = 0x%x \n",rmi_dev->driver);
return 1;
}
- pr_info(" names DO NOT match, so return nothing \n");
+ pr_info("names DO NOT match, so return nothing\n");
return 0;
}
@@ -151,9 +149,9 @@ int rmi_register_phys_device(struct rmi_phys_device *phys)
dev_set_name(&rmi_dev->dev, "sensor%02d", phys_device_num++);
phys->rmi_dev = rmi_dev;
- pr_info(" registering physical device:\n");
- pr_info(" dev.init_name = \n", rmi_dev->dev.init_name);
- pr_info(" dev.bus->name = \n", rmi_dev->dev.bus->name);
+ pr_info("registering physical device:\n");
+ pr_info("dev.init_name = %s\n", rmi_dev->dev.init_name);
+ pr_info("dev.bus->name = %s\n", rmi_dev->dev.bus->name);
return device_register(&rmi_dev->dev);
}
EXPORT_SYMBOL(rmi_register_phys_device);
diff --git a/drivers/input/touchscreen/rmi4/rmi_f09.c b/drivers/input/touchscreen/rmi4/rmi_f09.c
index 0ec980d..4328d49 100644
--- a/drivers/input/touchscreen/rmi4/rmi_f09.c
+++ b/drivers/input/touchscreen/rmi4/rmi_f09.c
@@ -86,13 +86,13 @@ static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
struct device_attribute *attr,
- char *buf, size_t count);
-
-static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
- struct device_attribute *attr, char *buf);
+ const char *buf, size_t count);
static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
struct device_attribute *attr, char *buf);
+#if defined(RMI_SYS_ATTR)
+static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_Overall_BIST_Result_show(struct device *dev,
struct device_attribute *attr, char *buf);
@@ -100,6 +100,7 @@ static ssize_t rmi_f09_Overall_BIST_Result_show(struct device *dev,
static ssize_t rmi_f09_Overall_BIST_Result_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
+#endif
static struct device_attribute attrs[] = {
__ATTR(Limit_Register_Count, RMI_RO_ATTR,
@@ -119,7 +120,6 @@ static int rmi_f09_init(struct rmi_function_container *fc)
struct rmi_fn_09_data *f09;
u8 query_base_addr;
int rc;
- int i;
int attr_count = 0;
int retval = 0;
@@ -171,8 +171,8 @@ static void rmi_f09_remove(struct rmi_function_container *fc)
{
struct rmi_fn_09_data *data = fc->data;
if (data) {
- kfree(data->query.Limit_Register_Count);
- kfree(data->query.f09_bist_query1);
+ kfree(&data->query.Limit_Register_Count);
+ kfree(&data->query.f09_bist_query1);
}
kfree(fc->data);
}
@@ -230,7 +230,7 @@ static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
struct device_attribute *attr,
- char *buf, size_t count)
+ const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
@@ -264,7 +264,8 @@ static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
}
-static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+#if defined(RMI_SYS_ATTR)
+ ssize_t rmi_f09_InternalLimits_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@@ -276,6 +277,7 @@ static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n",
data->query.InternalLimits);
}
+#endif
static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
struct device_attribute *attr,
diff --git a/drivers/input/touchscreen/rmi4/rmi_spi.c b/drivers/input/touchscreen/rmi4/rmi_spi.c
index 41f7265..71c98bc 100644
--- a/drivers/input/touchscreen/rmi4/rmi_spi.c
+++ b/drivers/input/touchscreen/rmi4/rmi_spi.c
@@ -523,19 +523,16 @@ static int rmi_spi_v2_set_page(struct rmi_phys_device *phys, u8 page)
static int acquire_attn_irq(struct rmi_spi_data *data)
{
int retval = 0;
- pr_info("in function ____%s____ \n", __func__);
- pr_info(" irq = %d\n", data->irq);
- pr_info(" rmi_spi_hard_irq = 0x%8x\n", rmi_spi_hard_irq);
- pr_info(" rmi_spi_irq_thread = 0x%8x\n", rmi_spi_irq_thread);
- pr_info(" data->irq_flags = 0x%8x\n", data->irq_flags);
- pr_info(" dev_name(data->phys->dev) = %s\n", dev_name(data->phys->dev));
- pr_info(" data->phys = 0x%8x\n", data->phys);
+ pr_info("in function ____%s____\n", __func__);
+ pr_info("irq = %d\n", data->irq);
+ pr_info("data->irq_flags = 0x%8x\n", data->irq_flags);
+ pr_info("dev_name(data->phys->dev) = %s\n", dev_name(data->phys->dev));
retval = request_threaded_irq(data->irq, rmi_spi_hard_irq,
rmi_spi_irq_thread, data->irq_flags,
dev_name(data->phys->dev), data->phys);
- pr_info(" retval = = %d\n", retval);
+ pr_info("retval = %d\n", retval);
return retval;
}
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
index c33557c..618f1bf 100644
--- a/drivers/iommu/tegra-gart.c
+++ b/drivers/iommu/tegra-gart.c
@@ -246,7 +246,7 @@ static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova,
pfn = __phys_to_pfn(pa);
if (!pfn_valid(pfn)) {
dev_err(gart->dev, "Invalid page: %08x\n", pa);
- spin_lock_irqsave(&gart->pte_lock, flags);
+ spin_unlock_irqrestore(&gart->pte_lock, flags);
return -EINVAL;
}
gart_set_pte(gart, iova, GART_PTE(pfn));
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index f4d859f..bf33c030 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -734,7 +734,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n");
}
- dev_dbg(smmu->dev, "%s is attached\n", dev_name(c->dev));
+ dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev));
return 0;
err_client:
diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig
index 404d771..f5aea996 100644
--- a/drivers/media/video/tegra/Kconfig
+++ b/drivers/media/video/tegra/Kconfig
@@ -27,6 +27,13 @@ config VIDEO_OV5650
This is a driver for the Omnivision OV5650 5MP camera sensor
for use with the tegra isp.
+config VIDEO_OV5640
+ tristate "OV5640 camera sensor support"
+ depends on I2C && ARCH_TEGRA
+ ---help---
+ This is a driver for the Omnivision OV5640 5MP camera sensor
+ for use with the tegra isp.
+
config VIDEO_OV14810
tristate "OV14810 camera sensor support"
depends on I2C && ARCH_TEGRA
diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile
index 5d404e4..08b81e2 100644
--- a/drivers/media/video/tegra/Makefile
+++ b/drivers/media/video/tegra/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_TEGRA_DTV) += tegra_dtv.o
obj-$(CONFIG_TEGRA_CAMERA) += tegra_camera.o
obj-$(CONFIG_VIDEO_AR0832) += ar0832_main.o
obj-$(CONFIG_VIDEO_OV5650) += ov5650.o
+obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
obj-$(CONFIG_VIDEO_OV14810) += ov14810.o
obj-$(CONFIG_VIDEO_OV9726) += ov9726.o
obj-$(CONFIG_VIDEO_OV2710) += ov2710.o
diff --git a/drivers/media/video/tegra/ad5820.c b/drivers/media/video/tegra/ad5820.c
index 19d35bc..adfda3e 100644
--- a/drivers/media/video/tegra/ad5820.c
+++ b/drivers/media/video/tegra/ad5820.c
@@ -228,4 +228,4 @@ static void __exit ad5820_exit(void)
module_init(ad5820_init);
module_exit(ad5820_exit);
-
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/ar0832_main.c b/drivers/media/video/tegra/ar0832_main.c
index 129825c..f3b56bb 100644
--- a/drivers/media/video/tegra/ar0832_main.c
+++ b/drivers/media/video/tegra/ar0832_main.c
@@ -738,7 +738,7 @@ static struct ar0832_reg mode_1920X1080_8140[] = {
{0x3178, 0x0000}, /* RESERVED_MFR_3178 */
{0x3ED0, 0x1E24}, /* RESERVED_MFR_3ED0 */
- {0x0342, 0x103B}, /* LINE_LENGTH_PCK */
+ {0x0342, 0x1139}, /* LINE_LENGTH_PCK */
{0x0340, 0x05C4}, /* FRAME_LENGTH_LINES */
{0x0202, 0x05C4}, /* COARSE_INTEGRATION_TIME */
{0x3014, 0x0702}, /* FINE_INTEGRATION_TIME */
@@ -863,7 +863,7 @@ static struct ar0832_reg mode_1920X1080_8141[] = {
{0x3178, 0x0000}, /* RESERVED_MFR_3178 */
{0x3ED0, 0x1E24}, /* RESERVED_MFR_3ED0 */
- {0x0342, 0x103B}, /* LINE_LENGTH_PCK */
+ {0x0342, 0x1139}, /* LINE_LENGTH_PCK */
{0x0340, 0x05C4}, /* FRAME_LENGTH_LINES */
{0x0202, 0x05C4}, /* COARSE_INTEGRATION_TIME */
{0x3014, 0x0702}, /* FINE_INTEGRATION_TIME */
@@ -1977,7 +1977,7 @@ static int ar0832_focuser_set_position(struct ar0832_dev *dev,
return ret;
}
-
+#ifdef AR0832_FOCUSER_DYNAMIC_STEP_TIME
/*
* This function is not currently called as we have the hardcoded
* step time in ar0832_focuser_set_config function. If we need to
@@ -2033,6 +2033,7 @@ static u16 ar0832_get_focuser_vcm_step_time(struct ar0832_dev *dev)
return vt_pix_clk_freq_mhz;
}
+#endif
static inline
int ar0832_get_sensorid(struct ar0832_dev *dev, u16 *sensor_id)
@@ -2148,7 +2149,6 @@ static long ar0832_ioctl(struct file *file,
}
case AR0832_IOCTL_SET_SENSOR_REGION:
{
- struct ar0832_stereo_region region;
dev_dbg(&i2c_client->dev, "AR0832_IOCTL_SET_SENSOR_REGION\n");
/* Right now, it doesn't do anything */
@@ -2547,3 +2547,4 @@ static void __exit ar0832_exit(void)
module_init(ar0832_init);
module_exit(ar0832_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/avp/avp.c b/drivers/media/video/tegra/avp/avp.c
index 074a42f..fc965e4 100644
--- a/drivers/media/video/tegra/avp/avp.c
+++ b/drivers/media/video/tegra/avp/avp.c
@@ -42,7 +42,7 @@
#include <mach/clk.h>
#include <mach/io.h>
#include <mach/iomap.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/legacy_irq.h>
#include <mach/hardware.h>
diff --git a/drivers/media/video/tegra/avp/avp_svc.c b/drivers/media/video/tegra/avp/avp_svc.c
index 17c8b85..1e82199 100644
--- a/drivers/media/video/tegra/avp/avp_svc.c
+++ b/drivers/media/video/tegra/avp/avp_svc.c
@@ -29,7 +29,7 @@
#include <linux/types.h>
#include <mach/clk.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "../../../../video/tegra/nvmap/nvmap.h"
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
index 4627c51..012f50b 100644
--- a/drivers/media/video/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c
@@ -40,9 +40,8 @@
#include <mach/io.h>
#include <mach/iomap.h>
#include <mach/legacy_irq.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
-#include "../../../../video/tegra/nvmap/nvmap.h"
#include "../../../../video/tegra/host/host1x/host1x_syncpt.h"
#include "../../../../video/tegra/host/dev.h"
#include "../../../../video/tegra/host/nvhost_acm.h"
@@ -118,6 +117,7 @@ struct nvavp_info {
struct nvhost_device *nvhost_dev;
struct miscdevice misc_dev;
+ atomic_t clock_stay_on_refcount;
};
struct nvavp_clientctx {
@@ -127,7 +127,7 @@ struct nvavp_clientctx {
struct nvmap_handle_ref *gather_mem;
int num_relocs;
struct nvavp_info *nvavp;
- u32 clk_reqs;
+ int clock_stay_on;
};
static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id)
@@ -176,7 +176,8 @@ static void nvavp_clks_disable(struct nvavp_info *nvavp)
static u32 nvavp_check_idle(struct nvavp_info *nvavp)
{
struct nv_e276_control *control = nvavp->os_control;
- return (control->put == control->get) ? 1 : 0;
+ return ((control->put == control->get)
+ && (!atomic_read(&nvavp->clock_stay_on_refcount))) ? 1 : 0;
}
static void clock_disable_handler(struct work_struct *work)
@@ -1061,15 +1062,16 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
return -EINVAL;
}
- mutex_lock(&nvavp->open_lock);
- if (clock.state) {
- if (clientctx->clk_reqs++ == 0)
- nvavp_clks_enable(nvavp);
- } else {
- if (--clientctx->clk_reqs == 0)
- nvavp_clks_disable(nvavp);
- }
- mutex_unlock(&nvavp->open_lock);
+ if (clientctx->clock_stay_on == clock.state)
+ return 0;
+
+ clientctx->clock_stay_on = clock.state;
+
+ if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_ENABLED)
+ atomic_inc(&nvavp->clock_stay_on_refcount);
+ else if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_DISABLED)
+ atomic_dec(&nvavp->clock_stay_on_refcount);
+
return 0;
}
@@ -1098,6 +1100,7 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
clientctx->nvmap = nvavp->nvmap;
clientctx->nvavp = nvavp;
+ clientctx->clock_stay_on = NVAVP_CLOCK_STAY_ON_DISABLED;
filp->private_data = clientctx;
@@ -1125,10 +1128,8 @@ static int tegra_nvavp_release(struct inode *inode, struct file *filp)
goto out;
}
- /* if this client had any requests, drop our clk ref */
- if (clientctx->clk_reqs)
- nvavp_clks_disable(nvavp);
-
+ if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_ENABLED)
+ atomic_dec(&nvavp->clock_stay_on_refcount);
if (nvavp->refcount > 0)
nvavp->refcount--;
if (!nvavp->refcount)
@@ -1187,7 +1188,8 @@ static const struct file_operations tegra_nvavp_fops = {
.unlocked_ioctl = tegra_nvavp_ioctl,
};
-static int tegra_nvavp_probe(struct nvhost_device *ndev)
+static int tegra_nvavp_probe(struct nvhost_device *ndev,
+ struct nvhost_device_id *id_table)
{
struct nvavp_info *nvavp;
int irq;
@@ -1234,17 +1236,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev)
switch (heap_mask) {
case NVMAP_HEAP_IOVMM:
-#ifdef CONFIG_TEGRA_SMMU_BASE_AT_E0000000
- iovmm_addr = 0xeff00000;
-#else
iovmm_addr = 0x0ff00000;
-#endif
-
- /* Tegra3 A01 has different SMMU address */
- if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3
- && tegra_get_revision() == TEGRA_REVISION_A01) {
- iovmm_addr = 0xeff00000;
- }
nvavp->os_info.handle = nvmap_alloc_iovm(nvavp->nvmap, SZ_1M,
L1_CACHE_BYTES,
diff --git a/drivers/media/video/tegra/ov14810.c b/drivers/media/video/tegra/ov14810.c
index 2efd283..8a72cd7 100644
--- a/drivers/media/video/tegra/ov14810.c
+++ b/drivers/media/video/tegra/ov14810.c
@@ -1387,4 +1387,4 @@ static void __exit ov14810_exit(void)
module_init(ov14810_init);
module_exit(ov14810_exit);
-
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/ov2710.c b/drivers/media/video/tegra/ov2710.c
index a2e0236..5e8eaa1 100644
--- a/drivers/media/video/tegra/ov2710.c
+++ b/drivers/media/video/tegra/ov2710.c
@@ -687,4 +687,4 @@ static void __exit ov2710_exit(void)
module_init(ov2710_init);
module_exit(ov2710_exit);
-
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/ov5640.c b/drivers/media/video/tegra/ov5640.c
new file mode 100644
index 00000000..b20c036
--- /dev/null
+++ b/drivers/media/video/tegra/ov5640.c
@@ -0,0 +1,491 @@
+/*
+ * ov5640.c - ov5640 sensor driver
+ *
+ * Copyright (c) 2011 - 2012, NVIDIA, All Rights Reserved.
+ *
+ * Contributors:
+ * Abhinav Sinha <absinha@nvidia.com>
+ *
+ * Leverage soc380.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/**
+ * SetMode Sequence for 640x480. Phase 0. Sensor Dependent.
+ * This sequence should put sensor in streaming mode for 640x480
+ * This is usually given by the FAE or the sensor vendor.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <media/ov5640.h>
+
+#include "ov5640_tables.h"
+
+/* Focuser single step & full scale transition time truth table
+ * in the format of:
+ * index mode single step transition full scale transition
+ * 0 0 0 0
+ * 1 1 50uS 51.2mS
+ * 2 1 100uS 102.3mS
+ * 3 1 200uS 204.6mS
+ * 4 1 400uS 409.2mS
+ * 5 1 800uS 818.4mS
+ * 6 1 1600uS 1637.0mS
+ * 7 1 3200uS 3274.0mS
+ * 8 0 0 0
+ * 9 2 50uS 1.1mS
+ * A 2 100uS 2.2mS
+ * B 2 200uS 4.4mS
+ * C 2 400uS 8.8mS
+ * D 2 800uS 17.6mS
+ * E 2 1600uS 35.2mS
+ * F 2 3200uS 70.4mS
+ */
+
+/* pick up the mode index setting and its settle time from the above table */
+#define OV5640_VCM_DACMODE 0x3602
+#define OV5640_TRANSITION_MODE 0x0B
+#define SETTLETIME_MS 5
+
+#define POS_LOW (0)
+#define POS_HIGH (1023)
+#define FPOS_COUNT 1024
+#define FOCAL_LENGTH (10.0f)
+#define FNUMBER (2.8f)
+
+#define SIZEOF_I2C_TRANSBUF 64
+
+struct ov5640_info {
+ int mode;
+ struct miscdevice miscdev_info;
+ struct i2c_client *i2c_client;
+ struct ov5640_platform_data *pdata;
+ struct ov5640_config focuser;
+ int af_fw_loaded;
+ struct kobject *kobj;
+ struct device *dev;
+ u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
+};
+
+static int ov5640_read_reg(struct i2c_client *client, u16 addr, u8 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[3];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = data + 2;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+
+ if (err != 2)
+ return -EINVAL;
+
+ *val = data[2];
+
+ return 0;
+}
+
+static int ov5640_write_reg(struct i2c_client *client, u8 addr, u8 value)
+{
+ int count;
+ struct i2c_msg msg[1];
+ unsigned char data[4];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data[0] = addr;
+ data[1] = (u8) (addr & 0xff);
+ data[2] = value;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 3;
+ msg[0].buf = data;
+
+ count = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (count == ARRAY_SIZE(msg))
+ return 0;
+ dev_err(&client->dev,
+ "ov5840: i2c transfer failed, addr: %x, value: %02x\n",
+ addr, (u32)value);
+ return -EIO;
+}
+
+static int ov5640_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ dev_err(&client->dev, "ov5640: i2c transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ov5640_write_table(struct ov5640_info *info,
+ struct ov5640_reg table[],
+ struct ov5640_reg override_list[],
+ int num_override_regs)
+{
+ int err;
+ struct ov5640_reg *next, *n_next;
+ u8 *b_ptr = info->i2c_trans_buf;
+ unsigned int buf_filled = 0;
+ int i;
+ u16 val;
+
+ for (next = table; next->addr != OV5640_TABLE_END; next++) {
+ if (next->addr == OV5640_TABLE_WAIT_MS) {
+ msleep(next->val);
+ continue;
+ }
+
+ val = next->val;
+
+ /* When an override list is passed in, replace the reg */
+ /* value to write if the reg is in the list */
+ if (override_list) {
+ for (i = 0; i < num_override_regs; i++) {
+ if (next->addr == override_list[i].addr) {
+ val = override_list[i].val;
+ break;
+ }
+ }
+ }
+
+ if (!buf_filled) {
+ b_ptr = info->i2c_trans_buf;
+ *b_ptr++ = next->addr >> 8;
+ *b_ptr++ = next->addr & 0xff;
+ buf_filled = 2;
+ }
+ *b_ptr++ = val;
+ buf_filled++;
+
+ n_next = next + 1;
+ if (n_next->addr != OV5640_TABLE_END &&
+ n_next->addr != OV5640_TABLE_WAIT_MS &&
+ buf_filled < SIZEOF_I2C_TRANSBUF &&
+ n_next->addr == next->addr + 1) {
+ continue;
+ }
+
+ err = ov5640_write_bulk_reg(info->i2c_client,
+ info->i2c_trans_buf, buf_filled);
+ if (err)
+ return err;
+
+ buf_filled = 0;
+ }
+ return 0;
+}
+
+static int ov5640_set_mode(struct ov5640_info *info, struct ov5640_mode *mode)
+{
+ int sensor_mode;
+ int err;
+
+ dev_info(info->dev, "%s: xres %u yres %u\n",
+ __func__, mode->xres, mode->yres);
+ if (!info->af_fw_loaded) {
+ err = ov5640_write_table(info, tbl_af_firmware, NULL, 0);
+ if (err)
+ return err;
+ info->af_fw_loaded = 1;
+ }
+
+ if (mode->xres == 2592 && mode->yres == 1944)
+ sensor_mode = OV5640_MODE_2592x1944;
+ else if (mode->xres == 1920 && mode->yres == 1080)
+ sensor_mode = OV5640_MODE_1920x1080;
+ else if (mode->xres == 1296 && mode->yres == 964)
+ sensor_mode = OV5640_MODE_1296x972;
+ else {
+ dev_info(info->dev, "%s: invalid resolution: %d %d\n",
+ __func__, mode->xres, mode->yres);
+ return -EINVAL;
+ }
+
+ err = ov5640_write_table(info, mode_table[sensor_mode],
+ NULL, 0);
+ if (err)
+ return err;
+
+ info->mode = sensor_mode;
+ return 0;
+}
+
+static int ov5640_set_af_mode(struct ov5640_info *info, u8 mode)
+{
+ dev_info(info->dev, "%s: mode %d\n", __func__, mode);
+ if (mode == OV5640_AF_INIFINITY)
+ return ov5640_write_table(info, tbl_release_focus, NULL, 0);
+
+ if (mode == OV5640_AF_TRIGGER)
+ return ov5640_write_table(info, tbl_single_focus, NULL, 0);
+
+ return -EINVAL;
+}
+
+static int ov5640_get_af_status(struct ov5640_info *info, u8 *val)
+{
+ int err;
+
+ err = ov5640_read_reg(info->i2c_client, 0x3023, val);
+ if (err)
+ return -EINVAL;
+
+ dev_info(info->dev, "%s: value %02x\n", __func__, (u32)val);
+ return 0;
+}
+
+static int ov5640_set_position(struct ov5640_info *info, u32 position)
+{
+ u8 data[4];
+
+ if (position < info->focuser.pos_low ||
+ position > info->focuser.pos_high)
+ return -EINVAL;
+
+ data[0] = (OV5640_VCM_DACMODE >> 8) & 0xff;
+ data[1] = OV5640_VCM_DACMODE & 0xff;
+ data[2] = ((position & 0xf) << 4) | OV5640_TRANSITION_MODE;
+ data[3] = (position * 0x3f0) >> 4;
+ return ov5640_write_bulk_reg(info->i2c_client, data, 4);
+}
+
+static int ov5640_set_power(struct ov5640_info *info, u32 level)
+{
+ switch (level) {
+ case OV5640_POWER_LEVEL_OFF:
+ case OV5640_POWER_LEVEL_SUS:
+ if (info->pdata && info->pdata->power_off)
+ info->pdata->power_off();
+ info->af_fw_loaded = 0;
+ info->mode = 0;
+ break;
+ case OV5640_POWER_LEVEL_ON:
+ if (info->pdata && info->pdata->power_on)
+ info->pdata->power_on();
+ break;
+ default:
+ dev_err(info->dev, "unknown power level %d.\n", level);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static long ov5640_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ov5640_info *info = file->private_data;
+
+ switch (cmd) {
+ case OV5640_IOCTL_SET_SENSOR_MODE:
+ {
+ struct ov5640_mode mode;
+ if (copy_from_user(&mode,
+ (const void __user *)arg,
+ sizeof(struct ov5640_mode))) {
+ return -EFAULT;
+ }
+
+ return ov5640_set_mode(info, &mode);
+ }
+ case OV5640_IOCTL_GET_CONFIG:
+ {
+ if (copy_to_user((void __user *) arg,
+ &info->focuser,
+ sizeof(info->focuser))) {
+ dev_err(info->dev, "%s: 0x%x\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ break;
+ }
+ case OV5640_IOCTL_GET_AF_STATUS:
+ {
+ int err;
+ u8 val;
+
+ if (!info->af_fw_loaded) {
+ dev_err(info->dev, "OV5640 AF fw not loaded!\n");
+ break;
+ }
+
+ err = ov5640_get_af_status(info, &val);
+ if (err)
+ return err;
+
+ if (copy_to_user((void __user *) arg,
+ &val, sizeof(val))) {
+ dev_err(info->dev, "%s: 0x%x\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ break;
+ }
+ case OV5640_IOCTL_SET_AF_MODE:
+ if (!info->af_fw_loaded) {
+ dev_err(info->dev, "OV5640 AF fw not loaded!\n");
+ break;
+ }
+ return ov5640_set_af_mode(info, (u8)arg);
+ case OV5640_IOCTL_POWER_LEVEL:
+ return ov5640_set_power(info, (u32)arg);
+ case OV5640_IOCTL_SET_FPOSITION:
+ return ov5640_set_position(info, (u32)arg);
+ case OV5640_IOCTL_GET_SENSOR_STATUS:
+ {
+ u8 status = 0;
+ if (copy_to_user((void __user *)arg, &status,
+ 1)) {
+ dev_info(info->dev, "%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ov5640_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct ov5640_info *info;
+
+ pr_info("%s\n", __func__);
+ if (!miscdev) {
+ pr_err("miscdev == NULL\n");
+ return -1;
+ }
+ info = container_of(miscdev, struct ov5640_info, miscdev_info);
+ file->private_data = info;
+
+ return 0;
+}
+
+int ov5640_release(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static const struct file_operations ov5640_fileops = {
+ .owner = THIS_MODULE,
+ .open = ov5640_open,
+ .unlocked_ioctl = ov5640_ioctl,
+ .release = ov5640_release,
+};
+
+static struct miscdevice ov5640_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ov5640",
+ .fops = &ov5640_fileops,
+};
+
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ov5640_info *info;
+ int err;
+
+ dev_info(&client->dev, "ov5640: probing sensor.\n");
+
+ info = devm_kzalloc(&client->dev,
+ sizeof(struct ov5640_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&client->dev, "ov5640: Unable to allocate memory!\n");
+ return -ENOMEM;
+ }
+
+ memcpy(&(info->miscdev_info),
+ &ov5640_device,
+ sizeof(struct miscdevice));
+
+ err = misc_register(&(info->miscdev_info));
+ if (err) {
+ dev_err(&client->dev,
+ "ov5640: Unable to register misc device!\n");
+ devm_kfree(&client->dev, info);
+ return err;
+ }
+
+ info->dev = &client->dev;
+ info->pdata = client->dev.platform_data;
+ info->i2c_client = client;
+ info->focuser.settle_time = SETTLETIME_MS;
+ info->focuser.focal_length = FOCAL_LENGTH;
+ info->focuser.fnumber = FNUMBER;
+ info->focuser.pos_low = POS_LOW;
+ info->focuser.pos_high = POS_HIGH;
+
+ i2c_set_clientdata(client, info);
+ return 0;
+}
+
+static int ov5640_remove(struct i2c_client *client)
+{
+ struct ov5640_info *info;
+ info = i2c_get_clientdata(client);
+ misc_deregister(&ov5640_device);
+ return 0;
+}
+
+static const struct i2c_device_id ov5640_id[] = {
+ { "ov5640", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .name = "ov5640",
+ .owner = THIS_MODULE,
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+module_i2c_driver(ov5640_i2c_driver);
diff --git a/drivers/media/video/tegra/ov5640_tables.h b/drivers/media/video/tegra/ov5640_tables.h
new file mode 100644
index 00000000..94cf1da3
--- /dev/null
+++ b/drivers/media/video/tegra/ov5640_tables.h
@@ -0,0 +1,4582 @@
+/*
+ * ov5640_tables.h - table header for YUV camera sensor OV5640 driver.
+ *
+ * Copyright (C) 2012 NVIDIA Corporation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#ifndef OV5640_I2C_TABLES
+#define OV5640_I2C_TABLES
+
+struct ov5640_reg {
+ u16 addr;
+ u16 val;
+};
+
+#define OV5640_TABLE_WAIT_MS 0
+#define OV5640_TABLE_END 1
+
+static struct ov5640_reg mode_2592x1944[] = {
+ /* PLL Control MIPI bit rate/lane = 672MHz, 16-bit mode.
+ * Output size: 2608x1948 (0, 0) - (2623, 1951),
+ * Line Length = 2844, Frame Length = 1968
+ */
+ {0x3103, 0x11},
+ {0x3008, 0x82},
+ {OV5640_TABLE_WAIT_MS, 5},
+ {0x3008, 0x42},
+ {0x3103, 0x03},
+ {0x3017, 0x00},
+ {0x3018, 0x00},
+ {0x3034, 0x18},
+ {0x3035, 0x11},
+ {0x3036, 0x54},
+ {0x3037, 0x13},
+ {0x3108, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3621, 0xe0},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x3901, 0x0a},
+ {0x3731, 0x12},
+ {0x3600, 0x08},
+ {0x3601, 0x33},
+ {0x302d, 0x60},
+ {0x3620, 0x52},
+ {0x371b, 0x20},
+ {0x471c, 0x50},
+ {0x3a13, 0x43},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3634, 0x40},
+ {0x3622, 0x01},
+ {0x3c01, 0x34},
+ {0x3c04, 0x28},
+ {0x3c05, 0x98},
+ {0x3c06, 0x00},
+ {0x3c07, 0x07},
+ {0x3c08, 0x00},
+ {0x3c09, 0x1c},
+ {0x3c0a, 0x9c},
+ {0x3c0b, 0x40},
+ {0x3820, 0x40},
+ {0x3821, 0x06},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x3808, 0x0a},
+ {0x3809, 0x30},
+ {0x380a, 0x07},
+ {0x380b, 0x9c},
+ {0x380c, 0x0b},
+ {0x380d, 0x1c},
+ {0x380e, 0x07},
+ {0x380f, 0xb0},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3618, 0x04},
+ {0x3612, 0x2b},
+ {0x3708, 0x64},
+ {0x3709, 0x12},
+ {0x370c, 0x00},
+ {0x3a02, 0x07},
+ {0x3a03, 0xb0},
+ {0x3a08, 0x01},
+ {0x3a09, 0x27},
+ {0x3a0a, 0x00},
+ {0x3a0b, 0xf6},
+ {0x3a0e, 0x06},
+ {0x3a0d, 0x08},
+ {0x3a14, 0x07},
+ {0x3a15, 0xb0},
+ {0x4001, 0x02},
+ {0x4004, 0x06},
+ {0x3000, 0x00},
+ {0x3002, 0x1c},
+ {0x3004, 0xff},
+ {0x3006, 0xc3},
+ {0x300e, 0x45},
+ {0x302e, 0x08},
+ {0x4300, 0x32},
+ {0x4800, 0x24},
+ {0x4837, 0x0a},
+ {0x501f, 0x00},
+ {0x440e, 0x00},
+ {0x5000, 0xa7},
+ {0x5001, 0x83},
+ {0x5180, 0xff},
+ {0x5181, 0xf2},
+ {0x5182, 0x00},
+ {0x5183, 0x14},
+ {0x5184, 0x25},
+ {0x5185, 0x24},
+ {0x5186, 0x09},
+ {0x5187, 0x09},
+ {0x5188, 0x09},
+ {0x5189, 0x75},
+ {0x518a, 0x54},
+ {0x518b, 0xe0},
+ {0x518c, 0xb2},
+ {0x518d, 0x42},
+ {0x518e, 0x3d},
+ {0x518f, 0x56},
+ {0x5190, 0x46},
+ {0x5191, 0xf8},
+ {0x5192, 0x04},
+ {0x5193, 0x70},
+ {0x5194, 0xf0},
+ {0x5195, 0xf0},
+ {0x5196, 0x03},
+ {0x5197, 0x01},
+ {0x5198, 0x04},
+ {0x5199, 0x12},
+ {0x519a, 0x04},
+ {0x519b, 0x00},
+ {0x519c, 0x06},
+ {0x519d, 0x82},
+ {0x519e, 0x38},
+ {0x5381, 0x1e},
+ {0x5382, 0x5b},
+ {0x5383, 0x08},
+ {0x5384, 0x0a},
+ {0x5385, 0x7e},
+ {0x5386, 0x88},
+ {0x5387, 0x7c},
+ {0x5388, 0x6c},
+ {0x5389, 0x10},
+ {0x538a, 0x01},
+ {0x538b, 0x98},
+ {0x5300, 0x08},
+ {0x5301, 0x30},
+ {0x5302, 0x10},
+ {0x5303, 0x00},
+ {0x5304, 0x08},
+ {0x5305, 0x30},
+ {0x5306, 0x08},
+ {0x5307, 0x16},
+ {0x5309, 0x08},
+ {0x530a, 0x30},
+ {0x530b, 0x04},
+ {0x530c, 0x06},
+ {0x5480, 0x01},
+ {0x5481, 0x08},
+ {0x5482, 0x14},
+ {0x5483, 0x28},
+ {0x5484, 0x51},
+ {0x5485, 0x65},
+ {0x5486, 0x71},
+ {0x5487, 0x7d},
+ {0x5488, 0x87},
+ {0x5489, 0x91},
+ {0x548a, 0x9a},
+ {0x548b, 0xaa},
+ {0x548c, 0xb8},
+ {0x548d, 0xcd},
+ {0x548e, 0xdd},
+ {0x548f, 0xea},
+ {0x5490, 0x1d},
+ {0x5580, 0x02},
+ {0x5583, 0x40},
+ {0x5584, 0x10},
+ {0x5589, 0x10},
+ {0x558a, 0x00},
+ {0x558b, 0xf8},
+ {0x5800, 0x23},
+ {0x5801, 0x14},
+ {0x5802, 0x0f},
+ {0x5803, 0x0f},
+ {0x5804, 0x12},
+ {0x5805, 0x26},
+ {0x5806, 0x0c},
+ {0x5807, 0x08},
+ {0x5808, 0x05},
+ {0x5809, 0x05},
+ {0x580a, 0x08},
+ {0x580b, 0x0d},
+ {0x580c, 0x08},
+ {0x580d, 0x03},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x09},
+ {0x5812, 0x07},
+ {0x5813, 0x03},
+ {0x5814, 0x00},
+ {0x5815, 0x01},
+ {0x5816, 0x03},
+ {0x5817, 0x08},
+ {0x5818, 0x0d},
+ {0x5819, 0x08},
+ {0x581a, 0x05},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x0e},
+ {0x581e, 0x29},
+ {0x581f, 0x17},
+ {0x5820, 0x11},
+ {0x5821, 0x11},
+ {0x5822, 0x15},
+ {0x5823, 0x28},
+ {0x5824, 0x46},
+ {0x5825, 0x26},
+ {0x5826, 0x08},
+ {0x5827, 0x26},
+ {0x5828, 0x64},
+ {0x5829, 0x26},
+ {0x582a, 0x24},
+ {0x582b, 0x22},
+ {0x582c, 0x24},
+ {0x582d, 0x24},
+ {0x582e, 0x06},
+ {0x582f, 0x22},
+ {0x5830, 0x40},
+ {0x5831, 0x42},
+ {0x5832, 0x24},
+ {0x5833, 0x26},
+ {0x5834, 0x24},
+ {0x5835, 0x22},
+ {0x5836, 0x22},
+ {0x5837, 0x26},
+ {0x5838, 0x44},
+ {0x5839, 0x24},
+ {0x583a, 0x26},
+ {0x583b, 0x28},
+ {0x583c, 0x42},
+ {0x583d, 0xce},
+ {0x5025, 0x00},
+ {0x3a0f, 0x30},
+ {0x3a10, 0x28},
+ {0x3a1b, 0x30},
+ {0x3a1e, 0x26},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x14},
+ {0x3008, 0x02},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg mode_1920x1080[] = {
+ /* PLL Control MIPI bit rate/lane = 672MHz, 16-bit mode.
+ * Output size: 1936x1096 (336, 426) - (2287, 1529),
+ * Line Length = 2500, Frame Length = 1120.
+ */
+ {0x3103, 0x11},
+ {0x3008, 0x82},
+ {OV5640_TABLE_WAIT_MS, 5},
+ {0x3008, 0x42},
+ {0x3103, 0x03},
+ {0x3017, 0x00},
+ {0x3018, 0x00},
+ {0x3034, 0x18},
+ {0x3035, 0x11},
+ {0x3036, 0x54},
+ {0x3037, 0x13},
+ {0x3108, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3621, 0xe0},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x3901, 0x0a},
+ {0x3731, 0x12},
+ {0x3600, 0x08},
+ {0x3601, 0x33},
+ {0x302d, 0x60},
+ {0x3620, 0x52},
+ {0x371b, 0x20},
+ {0x471c, 0x50},
+ {0x3a13, 0x43},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3634, 0x40},
+ {0x3622, 0x01},
+ {0x3c01, 0x34},
+ {0x3c04, 0x28},
+ {0x3c05, 0x98},
+ {0x3c06, 0x00},
+ {0x3c07, 0x07},
+ {0x3c08, 0x00},
+ {0x3c09, 0x1c},
+ {0x3c0a, 0x9c},
+ {0x3c0b, 0x40},
+ {0x3820, 0x40},
+ {0x3821, 0x06},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3800, 0x01},
+ {0x3801, 0x50},
+ {0x3802, 0x01},
+ {0x3803, 0xaa},
+ {0x3804, 0x08},
+ {0x3805, 0xef},
+ {0x3806, 0x05},
+ {0x3807, 0xf9},
+ {0x3808, 0x07},
+ {0x3809, 0x90},
+ {0x380a, 0x04},
+ {0x380b, 0x48},
+ {0x380c, 0x09},
+ {0x380d, 0xc4},
+ {0x380e, 0x04},
+ {0x380f, 0x60},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x04},
+ {0x3618, 0x04},
+ {0x3612, 0x2b},
+ {0x3708, 0x64},
+ {0x3709, 0x12},
+ {0x370c, 0x00},
+ {0x3a02, 0x04},
+ {0x3a03, 0x60},
+ {0x3a08, 0x01},
+ {0x3a09, 0x50},
+ {0x3a0a, 0x01},
+ {0x3a0b, 0x18},
+ {0x3a0e, 0x03},
+ {0x3a0d, 0x04},
+ {0x3a14, 0x04},
+ {0x3a15, 0x60},
+ {0x4001, 0x02},
+ {0x4004, 0x06},
+ {0x3000, 0x00},
+ {0x3002, 0x1c},
+ {0x3004, 0xff},
+ {0x3006, 0xc3},
+ {0x300e, 0x45},
+ {0x302e, 0x08},
+ {0x4300, 0x32},
+ {0x501f, 0x00},
+ {0x4713, 0x02},
+ {0x4407, 0x04},
+ {0x440e, 0x00},
+ {0x460b, 0x37},
+ {0x460c, 0x20},
+ {0x4800, 0x24},
+ {0x4837, 0x0a},
+ {0x3824, 0x04},
+ {0x5000, 0xa7},
+ {0x5001, 0x83},
+ {0x5180, 0xff},
+ {0x5181, 0xf2},
+ {0x5182, 0x00},
+ {0x5183, 0x14},
+ {0x5184, 0x25},
+ {0x5185, 0x24},
+ {0x5186, 0x09},
+ {0x5187, 0x09},
+ {0x5188, 0x09},
+ {0x5189, 0x75},
+ {0x518a, 0x54},
+ {0x518b, 0xe0},
+ {0x518c, 0xb2},
+ {0x518d, 0x42},
+ {0x518e, 0x3d},
+ {0x518f, 0x56},
+ {0x5190, 0x46},
+ {0x5191, 0xf8},
+ {0x5192, 0x04},
+ {0x5193, 0x70},
+ {0x5194, 0xf0},
+ {0x5195, 0xf0},
+ {0x5196, 0x03},
+ {0x5197, 0x01},
+ {0x5198, 0x04},
+ {0x5199, 0x12},
+ {0x519a, 0x04},
+ {0x519b, 0x00},
+ {0x519c, 0x06},
+ {0x519d, 0x82},
+ {0x519e, 0x38},
+ {0x5381, 0x1e},
+ {0x5382, 0x5b},
+ {0x5383, 0x08},
+ {0x5384, 0x0a},
+ {0x5385, 0x7e},
+ {0x5386, 0x88},
+ {0x5387, 0x7c},
+ {0x5388, 0x6c},
+ {0x5389, 0x10},
+ {0x538a, 0x01},
+ {0x538b, 0x98},
+ {0x5300, 0x08},
+ {0x5301, 0x30},
+ {0x5302, 0x10},
+ {0x5303, 0x00},
+ {0x5304, 0x08},
+ {0x5305, 0x30},
+ {0x5306, 0x08},
+ {0x5307, 0x16},
+ {0x5309, 0x08},
+ {0x530a, 0x30},
+ {0x530b, 0x04},
+ {0x530c, 0x06},
+ {0x5480, 0x01},
+ {0x5481, 0x08},
+ {0x5482, 0x14},
+ {0x5483, 0x28},
+ {0x5484, 0x51},
+ {0x5485, 0x65},
+ {0x5486, 0x71},
+ {0x5487, 0x7d},
+
+ {0x5488, 0x87},
+ {0x5489, 0x91},
+ {0x548a, 0x9a},
+ {0x548b, 0xaa},
+ {0x548c, 0xb8},
+ {0x548d, 0xcd},
+ {0x548e, 0xdd},
+ {0x548f, 0xea},
+ {0x5490, 0x1d},
+ {0x5580, 0x02},
+ {0x5583, 0x40},
+ {0x5584, 0x10},
+ {0x5589, 0x10},
+ {0x558a, 0x00},
+ {0x558b, 0xf8},
+ {0x5800, 0x23},
+ {0x5801, 0x14},
+ {0x5802, 0x0f},
+ {0x5803, 0x0f},
+ {0x5804, 0x12},
+ {0x5805, 0x26},
+ {0x5806, 0x0c},
+ {0x5807, 0x08},
+ {0x5808, 0x05},
+ {0x5809, 0x05},
+ {0x580a, 0x08},
+ {0x580b, 0x0d},
+ {0x580c, 0x08},
+ {0x580d, 0x03},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x09},
+ {0x5812, 0x07},
+ {0x5813, 0x03},
+ {0x5814, 0x00},
+ {0x5815, 0x01},
+ {0x5816, 0x03},
+ {0x5817, 0x08},
+ {0x5818, 0x0d},
+ {0x5819, 0x08},
+ {0x581a, 0x05},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x0e},
+ {0x581e, 0x29},
+ {0x581f, 0x17},
+ {0x5820, 0x11},
+ {0x5821, 0x11},
+ {0x5822, 0x15},
+ {0x5823, 0x28},
+ {0x5824, 0x46},
+ {0x5825, 0x26},
+ {0x5826, 0x08},
+ {0x5827, 0x26},
+ {0x5828, 0x64},
+ {0x5829, 0x26},
+ {0x582a, 0x24},
+ {0x582b, 0x22},
+ {0x582c, 0x24},
+ {0x582d, 0x24},
+ {0x582e, 0x06},
+ {0x582f, 0x22},
+ {0x5830, 0x40},
+ {0x5831, 0x42},
+ {0x5832, 0x24},
+ {0x5833, 0x26},
+ {0x5834, 0x24},
+ {0x5835, 0x22},
+ {0x5836, 0x22},
+ {0x5837, 0x26},
+ {0x5838, 0x44},
+ {0x5839, 0x24},
+ {0x583a, 0x26},
+ {0x583b, 0x28},
+ {0x583c, 0x42},
+ {0x583d, 0xce},
+ {0x5025, 0x00},
+ {0x3a0f, 0x30},
+ {0x3a10, 0x28},
+ {0x3a1b, 0x30},
+ {0x3a1e, 0x26},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x14},
+ {0x3008, 0x02},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg mode_1296x972[] = {
+ /* PLL Control MIPI bit rate/lane = 448MHz, 16-bit mode.
+ * Output size: 1304x972 (0, 0) - (2623, 1951),
+ * Line Length = 1886, Frame Length = 990.
+ */
+ {0x3103, 0x11},
+ {0x3008, 0x82},
+ {OV5640_TABLE_WAIT_MS, 5},
+ {0x3008, 0x42},
+ {0x3103, 0x03},
+ {0x3017, 0x00},
+ {0x3018, 0x00},
+ {0x3034, 0x18},
+ {0x3035, 0x21},
+ {0x3036, 0x70},
+ {0x3037, 0x13},
+ {0x3108, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3621, 0xe0},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x3901, 0x0a},
+ {0x3731, 0x12},
+ {0x3600, 0x08},
+ {0x3601, 0x33},
+ {0x302d, 0x60},
+ {0x3620, 0x52},
+ {0x371b, 0x20},
+ {0x471c, 0x50},
+ {0x3a13, 0x43},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3634, 0x40},
+ {0x3622, 0x01},
+ {0x3c01, 0x34},
+ {0x3c04, 0x28},
+ {0x3c05, 0x98},
+ {0x3c06, 0x00},
+ {0x3c07, 0x07},
+ {0x3c08, 0x00},
+ {0x3c09, 0x1c},
+ {0x3c0a, 0x9c},
+ {0x3c0b, 0x40},
+ {0x3820, 0x41},
+ {0x3821, 0x07},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x3808, 0x05},
+ {0x3809, 0x18},
+ {0x380a, 0x03},
+ {0x380b, 0xcc},
+ {0x380c, 0x07},
+ {0x380d, 0x5e},
+ {0x380e, 0x03},
+ {0x380f, 0xde},
+ {0x3810, 0x00},
+ {0x3811, 0x06},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3618, 0x00},
+ {0x3612, 0x29},
+ {0x3708, 0x62},
+ {0x3709, 0x52},
+ {0x370c, 0x03},
+ {0x3a02, 0x03},
+ {0x3a03, 0xd8},
+ {0x3a08, 0x01},
+ {0x3a09, 0x27},
+ {0x3a0a, 0x00},
+ {0x3a0b, 0xf6},
+ {0x3a0e, 0x03},
+ {0x3a0d, 0x04},
+ {0x3a14, 0x03},
+ {0x3a15, 0xd8},
+ {0x4001, 0x02},
+ {0x4004, 0x02},
+ {0x3000, 0x00},
+ {0x3002, 0x1c},
+ {0x3004, 0xff},
+ {0x3006, 0xc3},
+ {0x300e, 0x45},
+ {0x302e, 0x08},
+ {0x4300, 0x32},
+ {0x501f, 0x00},
+ {0x4713, 0x02},
+ {0x4407, 0x04},
+ {0x440e, 0x00},
+ {0x460b, 0x37},
+ {0x460c, 0x20},
+ {0x4800, 0x24},
+ {0x4837, 0x10},
+ {0x3824, 0x04},
+ {0x5000, 0xa7},
+ {0x5001, 0x83},
+ {0x5180, 0xff},
+ {0x5181, 0xf2},
+ {0x5182, 0x00},
+ {0x5183, 0x14},
+ {0x5184, 0x25},
+ {0x5185, 0x24},
+ {0x5186, 0x09},
+ {0x5187, 0x09},
+ {0x5188, 0x09},
+ {0x5189, 0x75},
+ {0x518a, 0x54},
+ {0x518b, 0xe0},
+ {0x518c, 0xb2},
+ {0x518d, 0x42},
+ {0x518e, 0x3d},
+ {0x518f, 0x56},
+ {0x5190, 0x46},
+ {0x5191, 0xf8},
+ {0x5192, 0x04},
+ {0x5193, 0x70},
+ {0x5194, 0xf0},
+ {0x5195, 0xf0},
+ {0x5196, 0x03},
+ {0x5197, 0x01},
+ {0x5198, 0x04},
+ {0x5199, 0x12},
+ {0x519a, 0x04},
+ {0x519b, 0x00},
+ {0x519c, 0x06},
+ {0x519d, 0x82},
+ {0x519e, 0x38},
+ {0x5381, 0x1e},
+ {0x5382, 0x5b},
+ {0x5383, 0x08},
+ {0x5384, 0x0a},
+ {0x5385, 0x7e},
+ {0x5386, 0x88},
+ {0x5387, 0x7c},
+ {0x5388, 0x6c},
+ {0x5389, 0x10},
+ {0x538a, 0x01},
+ {0x538b, 0x98},
+ {0x5300, 0x08},
+ {0x5301, 0x30},
+ {0x5302, 0x10},
+ {0x5303, 0x00},
+ {0x5304, 0x08},
+ {0x5305, 0x30},
+ {0x5306, 0x08},
+ {0x5307, 0x16},
+ {0x5309, 0x08},
+ {0x530a, 0x30},
+ {0x530b, 0x04},
+ {0x530c, 0x06},
+ {0x5480, 0x01},
+ {0x5481, 0x08},
+ {0x5482, 0x14},
+ {0x5483, 0x28},
+ {0x5484, 0x51},
+ {0x5485, 0x65},
+ {0x5486, 0x71},
+ {0x5487, 0x7d},
+ {0x5488, 0x87},
+ {0x5489, 0x91},
+ {0x548a, 0x9a},
+ {0x548b, 0xaa},
+ {0x548c, 0xb8},
+ {0x548d, 0xcd},
+ {0x548e, 0xdd},
+ {0x548f, 0xea},
+ {0x5490, 0x1d},
+ {0x5580, 0x02},
+ {0x5583, 0x40},
+ {0x5584, 0x10},
+ {0x5589, 0x10},
+ {0x558a, 0x00},
+ {0x558b, 0xf8},
+ {0x5800, 0x23},
+ {0x5801, 0x14},
+ {0x5802, 0x0f},
+ {0x5803, 0x0f},
+ {0x5804, 0x12},
+ {0x5805, 0x26},
+ {0x5806, 0x0c},
+ {0x5807, 0x08},
+ {0x5808, 0x05},
+ {0x5809, 0x05},
+ {0x580a, 0x08},
+ {0x580b, 0x0d},
+ {0x580c, 0x08},
+ {0x580d, 0x03},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x09},
+ {0x5812, 0x07},
+ {0x5813, 0x03},
+ {0x5814, 0x00},
+ {0x5815, 0x01},
+ {0x5816, 0x03},
+ {0x5817, 0x08},
+ {0x5818, 0x0d},
+ {0x5819, 0x08},
+ {0x581a, 0x05},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x0e},
+ {0x581e, 0x29},
+ {0x581f, 0x17},
+ {0x5820, 0x11},
+ {0x5821, 0x11},
+ {0x5822, 0x15},
+ {0x5823, 0x28},
+ {0x5824, 0x46},
+ {0x5825, 0x26},
+ {0x5826, 0x08},
+ {0x5827, 0x26},
+ {0x5828, 0x64},
+ {0x5829, 0x26},
+ {0x582a, 0x24},
+ {0x582b, 0x22},
+ {0x582c, 0x24},
+ {0x582d, 0x24},
+ {0x582e, 0x06},
+ {0x582f, 0x22},
+ {0x5830, 0x40},
+ {0x5831, 0x42},
+ {0x5832, 0x24},
+ {0x5833, 0x26},
+ {0x5834, 0x24},
+ {0x5835, 0x22},
+ {0x5836, 0x22},
+ {0x5837, 0x26},
+ {0x5838, 0x44},
+ {0x5839, 0x24},
+ {0x583a, 0x26},
+ {0x583b, 0x28},
+ {0x583c, 0x42},
+ {0x583d, 0xce},
+ {0x5025, 0x00},
+ {0x3a0f, 0x30},
+ {0x3a10, 0x28},
+ {0x3a1b, 0x30},
+ {0x3a1e, 0x26},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x14},
+ {0x3008, 0x02},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+enum {
+ OV5640_MODE_2592x1944 = 1,
+ OV5640_MODE_1920x1080,
+ OV5640_MODE_1296x972,
+};
+
+static struct ov5640_reg *mode_table[] = {
+ [OV5640_MODE_2592x1944] = mode_2592x1944,
+ [OV5640_MODE_1920x1080] = mode_1920x1080,
+ [OV5640_MODE_1296x972] = mode_1296x972,
+};
+
+static struct ov5640_reg tbl_af_firmware[] = {
+ {0x3000, 0x20},
+ {0x8000, 0x02},
+ {0x8001, 0x0b},
+ {0x8002, 0x1f},
+ {0x8003, 0x02},
+ {0x8004, 0x07},
+ {0x8005, 0x89},
+ {0x8006, 0xc2},
+ {0x8007, 0x01},
+ {0x8008, 0x22},
+ {0x8009, 0x22},
+ {0x800a, 0x00},
+ {0x800b, 0x02},
+ {0x800c, 0x0b},
+ {0x800d, 0x09},
+ {0x800e, 0xe5},
+ {0x800f, 0x40},
+ {0x8010, 0x60},
+ {0x8011, 0x03},
+ {0x8012, 0x02},
+ {0x8013, 0x00},
+ {0x8014, 0x97},
+ {0x8015, 0xf5},
+ {0x8016, 0x3f},
+ {0x8017, 0xd2},
+ {0x8018, 0x34},
+ {0x8019, 0x75},
+ {0x801a, 0x29},
+ {0x801b, 0xff},
+ {0x801c, 0x75},
+ {0x801d, 0x2a},
+ {0x801e, 0x0e},
+ {0x801f, 0x75},
+ {0x8020, 0x2b},
+ {0x8021, 0x55},
+ {0x8022, 0x75},
+ {0x8023, 0x2c},
+ {0x8024, 0x01},
+ {0x8025, 0x12},
+ {0x8026, 0x0a},
+ {0x8027, 0x0e},
+ {0x8028, 0xe4},
+ {0x8029, 0xff},
+ {0x802a, 0xef},
+ {0x802b, 0x25},
+ {0x802c, 0xe0},
+ {0x802d, 0x24},
+ {0x802e, 0x41},
+ {0x802f, 0xf8},
+ {0x8030, 0xe4},
+ {0x8031, 0xf6},
+ {0x8032, 0x08},
+ {0x8033, 0xf6},
+ {0x8034, 0x0f},
+ {0x8035, 0xbf},
+ {0x8036, 0x34},
+ {0x8037, 0xf2},
+ {0x8038, 0x90},
+ {0x8039, 0x0e},
+ {0x803a, 0x88},
+ {0x803b, 0xe4},
+ {0x803c, 0x93},
+ {0x803d, 0xff},
+ {0x803e, 0xe5},
+ {0x803f, 0x3e},
+ {0x8040, 0xc3},
+ {0x8041, 0x9f},
+ {0x8042, 0x50},
+ {0x8043, 0x04},
+ {0x8044, 0x7f},
+ {0x8045, 0x05},
+ {0x8046, 0x80},
+ {0x8047, 0x02},
+ {0x8048, 0x7f},
+ {0x8049, 0xfb},
+ {0x804a, 0x78},
+ {0x804b, 0xb0},
+ {0x804c, 0xa6},
+ {0x804d, 0x07},
+ {0x804e, 0x12},
+ {0x804f, 0x0a},
+ {0x8050, 0x78},
+ {0x8051, 0x40},
+ {0x8052, 0x04},
+ {0x8053, 0x7f},
+ {0x8054, 0x03},
+ {0x8055, 0x80},
+ {0x8056, 0x02},
+ {0x8057, 0x7f},
+ {0x8058, 0x30},
+ {0x8059, 0x78},
+ {0x805a, 0xaf},
+ {0x805b, 0xa6},
+ {0x805c, 0x07},
+ {0x805d, 0xe6},
+ {0x805e, 0x18},
+ {0x805f, 0xf6},
+ {0x8060, 0x08},
+ {0x8061, 0xe6},
+ {0x8062, 0x78},
+ {0x8063, 0xac},
+ {0x8064, 0xf6},
+ {0x8065, 0x78},
+ {0x8066, 0xaf},
+ {0x8067, 0xe6},
+ {0x8068, 0x78},
+ {0x8069, 0xad},
+ {0x806a, 0xf6},
+ {0x806b, 0x78},
+ {0x806c, 0xb2},
+ {0x806d, 0x76},
+ {0x806e, 0x33},
+ {0x806f, 0xe4},
+ {0x8070, 0x08},
+ {0x8071, 0xf6},
+ {0x8072, 0x78},
+ {0x8073, 0xab},
+ {0x8074, 0x76},
+ {0x8075, 0x01},
+ {0x8076, 0x75},
+ {0x8077, 0x3d},
+ {0x8078, 0x02},
+ {0x8079, 0x78},
+ {0x807a, 0xa9},
+ {0x807b, 0xf6},
+ {0x807c, 0x08},
+ {0x807d, 0xf6},
+ {0x807e, 0x74},
+ {0x807f, 0xff},
+ {0x8080, 0x78},
+ {0x8081, 0xb4},
+ {0x8082, 0xf6},
+ {0x8083, 0x08},
+ {0x8084, 0xf6},
+ {0x8085, 0x75},
+ {0x8086, 0x40},
+ {0x8087, 0x01},
+ {0x8088, 0x78},
+ {0x8089, 0xaf},
+ {0x808a, 0xe6},
+ {0x808b, 0x75},
+ {0x808c, 0xf0},
+ {0x808d, 0x05},
+ {0x808e, 0xa4},
+ {0x808f, 0xf5},
+ {0x8090, 0x3e},
+ {0x8091, 0x12},
+ {0x8092, 0x08},
+ {0x8093, 0x1d},
+ {0x8094, 0xc2},
+ {0x8095, 0x36},
+ {0x8096, 0x22},
+ {0x8097, 0x78},
+ {0x8098, 0xab},
+ {0x8099, 0xe6},
+ {0x809a, 0xd3},
+ {0x809b, 0x94},
+ {0x809c, 0x00},
+ {0x809d, 0x40},
+ {0x809e, 0x02},
+ {0x809f, 0x16},
+ {0x80a0, 0x22},
+ {0x80a1, 0xe5},
+ {0x80a2, 0x40},
+ {0x80a3, 0x64},
+ {0x80a4, 0x05},
+ {0x80a5, 0x70},
+ {0x80a6, 0x28},
+ {0x80a7, 0xf5},
+ {0x80a8, 0x40},
+ {0x80a9, 0xc2},
+ {0x80aa, 0x01},
+ {0x80ab, 0x78},
+ {0x80ac, 0xac},
+ {0x80ad, 0xe6},
+ {0x80ae, 0x25},
+ {0x80af, 0xe0},
+ {0x80b0, 0x24},
+ {0x80b1, 0x41},
+ {0x80b2, 0xf8},
+ {0x80b3, 0xe6},
+ {0x80b4, 0xfe},
+ {0x80b5, 0x08},
+ {0x80b6, 0xe6},
+ {0x80b7, 0xff},
+ {0x80b8, 0x78},
+ {0x80b9, 0x41},
+ {0x80ba, 0xa6},
+ {0x80bb, 0x06},
+ {0x80bc, 0x08},
+ {0x80bd, 0xa6},
+ {0x80be, 0x07},
+ {0x80bf, 0xa2},
+ {0x80c0, 0x36},
+ {0x80c1, 0xe4},
+ {0x80c2, 0x33},
+ {0x80c3, 0xf5},
+ {0x80c4, 0x31},
+ {0x80c5, 0x90},
+ {0x80c6, 0x30},
+ {0x80c7, 0x28},
+ {0x80c8, 0xf0},
+ {0x80c9, 0x75},
+ {0x80ca, 0x3f},
+ {0x80cb, 0x10},
+ {0x80cc, 0xd2},
+ {0x80cd, 0x34},
+ {0x80ce, 0x22},
+ {0x80cf, 0xe5},
+ {0x80d0, 0x3e},
+ {0x80d1, 0x75},
+ {0x80d2, 0xf0},
+ {0x80d3, 0x05},
+ {0x80d4, 0x84},
+ {0x80d5, 0x78},
+ {0x80d6, 0xaf},
+ {0x80d7, 0xf6},
+ {0x80d8, 0x90},
+ {0x80d9, 0x0e},
+ {0x80da, 0x85},
+ {0x80db, 0xe4},
+ {0x80dc, 0x93},
+ {0x80dd, 0xff},
+ {0x80de, 0x25},
+ {0x80df, 0xe0},
+ {0x80e0, 0x24},
+ {0x80e1, 0x0a},
+ {0x80e2, 0xf8},
+ {0x80e3, 0xe6},
+ {0x80e4, 0xfc},
+ {0x80e5, 0x08},
+ {0x80e6, 0xe6},
+ {0x80e7, 0xfd},
+ {0x80e8, 0x78},
+ {0x80e9, 0xaf},
+ {0x80ea, 0xe6},
+ {0x80eb, 0x25},
+ {0x80ec, 0xe0},
+ {0x80ed, 0x24},
+ {0x80ee, 0x41},
+ {0x80ef, 0xf8},
+ {0x80f0, 0xa6},
+ {0x80f1, 0x04},
+ {0x80f2, 0x08},
+ {0x80f3, 0xa6},
+ {0x80f4, 0x05},
+ {0x80f5, 0xef},
+ {0x80f6, 0x12},
+ {0x80f7, 0x0a},
+ {0x80f8, 0x7f},
+ {0x80f9, 0xd3},
+ {0x80fa, 0x78},
+ {0x80fb, 0xaa},
+ {0x80fc, 0x96},
+ {0x80fd, 0xee},
+ {0x80fe, 0x18},
+ {0x80ff, 0x96},
+ {0x8100, 0x40},
+ {0x8101, 0x0d},
+ {0x8102, 0x78},
+ {0x8103, 0xaf},
+ {0x8104, 0xe6},
+ {0x8105, 0x78},
+ {0x8106, 0xac},
+ {0x8107, 0xf6},
+ {0x8108, 0x78},
+ {0x8109, 0xa9},
+ {0x810a, 0xa6},
+ {0x810b, 0x06},
+ {0x810c, 0x08},
+ {0x810d, 0xa6},
+ {0x810e, 0x07},
+ {0x810f, 0x90},
+ {0x8110, 0x0e},
+ {0x8111, 0x85},
+ {0x8112, 0xe4},
+ {0x8113, 0x93},
+ {0x8114, 0x12},
+ {0x8115, 0x0a},
+ {0x8116, 0x7f},
+ {0x8117, 0xc3},
+ {0x8118, 0x78},
+ {0x8119, 0xb5},
+ {0x811a, 0x96},
+ {0x811b, 0xee},
+ {0x811c, 0x18},
+ {0x811d, 0x96},
+ {0x811e, 0x50},
+ {0x811f, 0x0d},
+ {0x8120, 0x78},
+ {0x8121, 0xaf},
+ {0x8122, 0xe6},
+ {0x8123, 0x78},
+ {0x8124, 0xad},
+ {0x8125, 0xf6},
+ {0x8126, 0x78},
+ {0x8127, 0xb4},
+ {0x8128, 0xa6},
+ {0x8129, 0x06},
+ {0x812a, 0x08},
+ {0x812b, 0xa6},
+ {0x812c, 0x07},
+ {0x812d, 0x78},
+ {0x812e, 0xa9},
+ {0x812f, 0xe6},
+ {0x8130, 0xfe},
+ {0x8131, 0x08},
+ {0x8132, 0xe6},
+ {0x8133, 0xc3},
+ {0x8134, 0x78},
+ {0x8135, 0xb5},
+ {0x8136, 0x96},
+ {0x8137, 0xff},
+ {0x8138, 0xee},
+ {0x8139, 0x18},
+ {0x813a, 0x96},
+ {0x813b, 0x78},
+ {0x813c, 0xb6},
+ {0x813d, 0xf6},
+ {0x813e, 0x08},
+ {0x813f, 0xa6},
+ {0x8140, 0x07},
+ {0x8141, 0x90},
+ {0x8142, 0x0e},
+ {0x8143, 0x8a},
+ {0x8144, 0xe4},
+ {0x8145, 0x18},
+ {0x8146, 0x12},
+ {0x8147, 0x0a},
+ {0x8148, 0x5d},
+ {0x8149, 0x40},
+ {0x814a, 0x02},
+ {0x814b, 0xd2},
+ {0x814c, 0x36},
+ {0x814d, 0x78},
+ {0x814e, 0xaf},
+ {0x814f, 0xe6},
+ {0x8150, 0x08},
+ {0x8151, 0x26},
+ {0x8152, 0x08},
+ {0x8153, 0xf6},
+ {0x8154, 0xe5},
+ {0x8155, 0x40},
+ {0x8156, 0x64},
+ {0x8157, 0x01},
+ {0x8158, 0x70},
+ {0x8159, 0x55},
+ {0x815a, 0xe6},
+ {0x815b, 0xc3},
+ {0x815c, 0x78},
+ {0x815d, 0xb3},
+ {0x815e, 0x12},
+ {0x815f, 0x0a},
+ {0x8160, 0x53},
+ {0x8161, 0x40},
+ {0x8162, 0x10},
+ {0x8163, 0x12},
+ {0x8164, 0x0a},
+ {0x8165, 0x4e},
+ {0x8166, 0x50},
+ {0x8167, 0x0b},
+ {0x8168, 0x30},
+ {0x8169, 0x36},
+ {0x816a, 0x41},
+ {0x816b, 0x78},
+ {0x816c, 0xaf},
+ {0x816d, 0xe6},
+ {0x816e, 0x78},
+ {0x816f, 0xac},
+ {0x8170, 0x66},
+ {0x8171, 0x60},
+ {0x8172, 0x39},
+ {0x8173, 0x12},
+ {0x8174, 0x0a},
+ {0x8175, 0x76},
+ {0x8176, 0x40},
+ {0x8177, 0x04},
+ {0x8178, 0x7f},
+ {0x8179, 0xfe},
+ {0x817a, 0x80},
+ {0x817b, 0x02},
+ {0x817c, 0x7f},
+ {0x817d, 0x02},
+ {0x817e, 0x78},
+ {0x817f, 0xb0},
+ {0x8180, 0xa6},
+ {0x8181, 0x07},
+ {0x8182, 0x78},
+ {0x8183, 0xac},
+ {0x8184, 0xe6},
+ {0x8185, 0x24},
+ {0x8186, 0x03},
+ {0x8187, 0x78},
+ {0x8188, 0xb2},
+ {0x8189, 0xf6},
+ {0x818a, 0x78},
+ {0x818b, 0xac},
+ {0x818c, 0xe6},
+ {0x818d, 0x24},
+ {0x818e, 0xfd},
+ {0x818f, 0x78},
+ {0x8190, 0xb3},
+ {0x8191, 0xf6},
+ {0x8192, 0x12},
+ {0x8193, 0x0a},
+ {0x8194, 0x76},
+ {0x8195, 0x40},
+ {0x8196, 0x06},
+ {0x8197, 0x78},
+ {0x8198, 0xb3},
+ {0x8199, 0xe6},
+ {0x819a, 0xff},
+ {0x819b, 0x80},
+ {0x819c, 0x04},
+ {0x819d, 0x78},
+ {0x819e, 0xb2},
+ {0x819f, 0xe6},
+ {0x81a0, 0xff},
+ {0x81a1, 0x78},
+ {0x81a2, 0xb1},
+ {0x81a3, 0xa6},
+ {0x81a4, 0x07},
+ {0x81a5, 0x75},
+ {0x81a6, 0x40},
+ {0x81a7, 0x02},
+ {0x81a8, 0x78},
+ {0x81a9, 0xab},
+ {0x81aa, 0x76},
+ {0x81ab, 0x01},
+ {0x81ac, 0x02},
+ {0x81ad, 0x02},
+ {0x81ae, 0x6e},
+ {0x81af, 0xe5},
+ {0x81b0, 0x40},
+ {0x81b1, 0x64},
+ {0x81b2, 0x02},
+ {0x81b3, 0x60},
+ {0x81b4, 0x03},
+ {0x81b5, 0x02},
+ {0x81b6, 0x02},
+ {0x81b7, 0x4e},
+ {0x81b8, 0x78},
+ {0x81b9, 0xb1},
+ {0x81ba, 0xe6},
+ {0x81bb, 0xff},
+ {0x81bc, 0xc3},
+ {0x81bd, 0x78},
+ {0x81be, 0xb3},
+ {0x81bf, 0x12},
+ {0x81c0, 0x0a},
+ {0x81c1, 0x54},
+ {0x81c2, 0x40},
+ {0x81c3, 0x08},
+ {0x81c4, 0x12},
+ {0x81c5, 0x0a},
+ {0x81c6, 0x4e},
+ {0x81c7, 0x50},
+ {0x81c8, 0x03},
+ {0x81c9, 0x02},
+ {0x81ca, 0x02},
+ {0x81cb, 0x4c},
+ {0x81cc, 0x12},
+ {0x81cd, 0x0a},
+ {0x81ce, 0x76},
+ {0x81cf, 0x40},
+ {0x81d0, 0x04},
+ {0x81d1, 0x7f},
+ {0x81d2, 0xff},
+ {0x81d3, 0x80},
+ {0x81d4, 0x02},
+ {0x81d5, 0x7f},
+ {0x81d6, 0x01},
+ {0x81d7, 0x78},
+ {0x81d8, 0xb0},
+ {0x81d9, 0xa6},
+ {0x81da, 0x07},
+ {0x81db, 0x78},
+ {0x81dc, 0xac},
+ {0x81dd, 0xe6},
+ {0x81de, 0x04},
+ {0x81df, 0x78},
+ {0x81e0, 0xb2},
+ {0x81e1, 0xf6},
+ {0x81e2, 0x78},
+ {0x81e3, 0xac},
+ {0x81e4, 0xe6},
+ {0x81e5, 0x14},
+ {0x81e6, 0x78},
+ {0x81e7, 0xb3},
+ {0x81e8, 0xf6},
+ {0x81e9, 0x18},
+ {0x81ea, 0x12},
+ {0x81eb, 0x0a},
+ {0x81ec, 0x78},
+ {0x81ed, 0x40},
+ {0x81ee, 0x04},
+ {0x81ef, 0xe6},
+ {0x81f0, 0xff},
+ {0x81f1, 0x80},
+ {0x81f2, 0x02},
+ {0x81f3, 0x7f},
+ {0x81f4, 0x00},
+ {0x81f5, 0x78},
+ {0x81f6, 0xb2},
+ {0x81f7, 0xa6},
+ {0x81f8, 0x07},
+ {0x81f9, 0xd3},
+ {0x81fa, 0x08},
+ {0x81fb, 0xe6},
+ {0x81fc, 0x64},
+ {0x81fd, 0x80},
+ {0x81fe, 0x94},
+ {0x81ff, 0x80},
+ {0x8200, 0x40},
+ {0x8201, 0x04},
+ {0x8202, 0xe6},
+ {0x8203, 0xff},
+ {0x8204, 0x80},
+ {0x8205, 0x02},
+ {0x8206, 0x7f},
+ {0x8207, 0x00},
+ {0x8208, 0x78},
+ {0x8209, 0xb3},
+ {0x820a, 0xa6},
+ {0x820b, 0x07},
+ {0x820c, 0xc3},
+ {0x820d, 0x18},
+ {0x820e, 0xe6},
+ {0x820f, 0x64},
+ {0x8210, 0x80},
+ {0x8211, 0x94},
+ {0x8212, 0xb3},
+ {0x8213, 0x50},
+ {0x8214, 0x04},
+ {0x8215, 0xe6},
+ {0x8216, 0xff},
+ {0x8217, 0x80},
+ {0x8218, 0x02},
+ {0x8219, 0x7f},
+ {0x821a, 0x33},
+ {0x821b, 0x78},
+ {0x821c, 0xb2},
+ {0x821d, 0xa6},
+ {0x821e, 0x07},
+ {0x821f, 0xc3},
+ {0x8220, 0x08},
+ {0x8221, 0xe6},
+ {0x8222, 0x64},
+ {0x8223, 0x80},
+ {0x8224, 0x94},
+ {0x8225, 0xb3},
+ {0x8226, 0x50},
+ {0x8227, 0x04},
+ {0x8228, 0xe6},
+ {0x8229, 0xff},
+ {0x822a, 0x80},
+ {0x822b, 0x02},
+ {0x822c, 0x7f},
+ {0x822d, 0x33},
+ {0x822e, 0x78},
+ {0x822f, 0xb3},
+ {0x8230, 0xa6},
+ {0x8231, 0x07},
+ {0x8232, 0x12},
+ {0x8233, 0x0a},
+ {0x8234, 0x76},
+ {0x8235, 0x40},
+ {0x8236, 0x06},
+ {0x8237, 0x78},
+ {0x8238, 0xb3},
+ {0x8239, 0xe6},
+ {0x823a, 0xff},
+ {0x823b, 0x80},
+ {0x823c, 0x04},
+ {0x823d, 0x78},
+ {0x823e, 0xb2},
+ {0x823f, 0xe6},
+ {0x8240, 0xff},
+ {0x8241, 0x78},
+ {0x8242, 0xb1},
+ {0x8243, 0xa6},
+ {0x8244, 0x07},
+ {0x8245, 0x75},
+ {0x8246, 0x40},
+ {0x8247, 0x03},
+ {0x8248, 0x78},
+ {0x8249, 0xab},
+ {0x824a, 0x76},
+ {0x824b, 0x01},
+ {0x824c, 0x80},
+ {0x824d, 0x20},
+ {0x824e, 0xe5},
+ {0x824f, 0x40},
+ {0x8250, 0x64},
+ {0x8251, 0x03},
+ {0x8252, 0x70},
+ {0x8253, 0x26},
+ {0x8254, 0x78},
+ {0x8255, 0xb1},
+ {0x8256, 0xe6},
+ {0x8257, 0xff},
+ {0x8258, 0xc3},
+ {0x8259, 0x78},
+ {0x825a, 0xb3},
+ {0x825b, 0x12},
+ {0x825c, 0x0a},
+ {0x825d, 0x54},
+ {0x825e, 0x40},
+ {0x825f, 0x05},
+ {0x8260, 0x12},
+ {0x8261, 0x0a},
+ {0x8262, 0x4e},
+ {0x8263, 0x40},
+ {0x8264, 0x09},
+ {0x8265, 0x78},
+ {0x8266, 0xac},
+ {0x8267, 0xe6},
+ {0x8268, 0x78},
+ {0x8269, 0xb1},
+ {0x826a, 0xf6},
+ {0x826b, 0x75},
+ {0x826c, 0x40},
+ {0x826d, 0x04},
+ {0x826e, 0x78},
+ {0x826f, 0xb1},
+ {0x8270, 0xe6},
+ {0x8271, 0x75},
+ {0x8272, 0xf0},
+ {0x8273, 0x05},
+ {0x8274, 0xa4},
+ {0x8275, 0xf5},
+ {0x8276, 0x3e},
+ {0x8277, 0x02},
+ {0x8278, 0x08},
+ {0x8279, 0x1d},
+ {0x827a, 0xe5},
+ {0x827b, 0x40},
+ {0x827c, 0xb4},
+ {0x827d, 0x04},
+ {0x827e, 0x1f},
+ {0x827f, 0x90},
+ {0x8280, 0x0e},
+ {0x8281, 0x89},
+ {0x8282, 0xe4},
+ {0x8283, 0x78},
+ {0x8284, 0xb6},
+ {0x8285, 0x12},
+ {0x8286, 0x0a},
+ {0x8287, 0x5d},
+ {0x8288, 0x40},
+ {0x8289, 0x02},
+ {0x828a, 0xd2},
+ {0x828b, 0x36},
+ {0x828c, 0x75},
+ {0x828d, 0x40},
+ {0x828e, 0x05},
+ {0x828f, 0x75},
+ {0x8290, 0x29},
+ {0x8291, 0xff},
+ {0x8292, 0x75},
+ {0x8293, 0x2a},
+ {0x8294, 0x0e},
+ {0x8295, 0x75},
+ {0x8296, 0x2b},
+ {0x8297, 0x59},
+ {0x8298, 0x75},
+ {0x8299, 0x2c},
+ {0x829a, 0x01},
+ {0x829b, 0x12},
+ {0x829c, 0x0a},
+ {0x829d, 0x0e},
+ {0x829e, 0x22},
+ {0x829f, 0xef},
+ {0x82a0, 0x8d},
+ {0x82a1, 0xf0},
+ {0x82a2, 0xa4},
+ {0x82a3, 0xa8},
+ {0x82a4, 0xf0},
+ {0x82a5, 0xcf},
+ {0x82a6, 0x8c},
+ {0x82a7, 0xf0},
+ {0x82a8, 0xa4},
+ {0x82a9, 0x28},
+ {0x82aa, 0xce},
+ {0x82ab, 0x8d},
+ {0x82ac, 0xf0},
+ {0x82ad, 0xa4},
+ {0x82ae, 0x2e},
+ {0x82af, 0xfe},
+ {0x82b0, 0x22},
+ {0x82b1, 0xbc},
+ {0x82b2, 0x00},
+ {0x82b3, 0x0b},
+ {0x82b4, 0xbe},
+ {0x82b5, 0x00},
+ {0x82b6, 0x29},
+ {0x82b7, 0xef},
+ {0x82b8, 0x8d},
+ {0x82b9, 0xf0},
+ {0x82ba, 0x84},
+ {0x82bb, 0xff},
+ {0x82bc, 0xad},
+ {0x82bd, 0xf0},
+ {0x82be, 0x22},
+ {0x82bf, 0xe4},
+ {0x82c0, 0xcc},
+ {0x82c1, 0xf8},
+ {0x82c2, 0x75},
+ {0x82c3, 0xf0},
+ {0x82c4, 0x08},
+ {0x82c5, 0xef},
+ {0x82c6, 0x2f},
+ {0x82c7, 0xff},
+ {0x82c8, 0xee},
+ {0x82c9, 0x33},
+ {0x82ca, 0xfe},
+ {0x82cb, 0xec},
+ {0x82cc, 0x33},
+ {0x82cd, 0xfc},
+ {0x82ce, 0xee},
+ {0x82cf, 0x9d},
+ {0x82d0, 0xec},
+ {0x82d1, 0x98},
+ {0x82d2, 0x40},
+ {0x82d3, 0x05},
+ {0x82d4, 0xfc},
+ {0x82d5, 0xee},
+ {0x82d6, 0x9d},
+ {0x82d7, 0xfe},
+ {0x82d8, 0x0f},
+ {0x82d9, 0xd5},
+ {0x82da, 0xf0},
+ {0x82db, 0xe9},
+ {0x82dc, 0xe4},
+ {0x82dd, 0xce},
+ {0x82de, 0xfd},
+ {0x82df, 0x22},
+ {0x82e0, 0xed},
+ {0x82e1, 0xf8},
+ {0x82e2, 0xf5},
+ {0x82e3, 0xf0},
+ {0x82e4, 0xee},
+ {0x82e5, 0x84},
+ {0x82e6, 0x20},
+ {0x82e7, 0xd2},
+ {0x82e8, 0x1c},
+ {0x82e9, 0xfe},
+ {0x82ea, 0xad},
+ {0x82eb, 0xf0},
+ {0x82ec, 0x75},
+ {0x82ed, 0xf0},
+ {0x82ee, 0x08},
+ {0x82ef, 0xef},
+ {0x82f0, 0x2f},
+ {0x82f1, 0xff},
+ {0x82f2, 0xed},
+ {0x82f3, 0x33},
+ {0x82f4, 0xfd},
+ {0x82f5, 0x40},
+ {0x82f6, 0x07},
+ {0x82f7, 0x98},
+ {0x82f8, 0x50},
+ {0x82f9, 0x06},
+ {0x82fa, 0xd5},
+ {0x82fb, 0xf0},
+ {0x82fc, 0xf2},
+ {0x82fd, 0x22},
+ {0x82fe, 0xc3},
+ {0x82ff, 0x98},
+ {0x8300, 0xfd},
+ {0x8301, 0x0f},
+ {0x8302, 0xd5},
+ {0x8303, 0xf0},
+ {0x8304, 0xea},
+ {0x8305, 0x22},
+ {0x8306, 0xe8},
+ {0x8307, 0x8f},
+ {0x8308, 0xf0},
+ {0x8309, 0xa4},
+ {0x830a, 0xcc},
+ {0x830b, 0x8b},
+ {0x830c, 0xf0},
+ {0x830d, 0xa4},
+ {0x830e, 0x2c},
+ {0x830f, 0xfc},
+ {0x8310, 0xe9},
+ {0x8311, 0x8e},
+ {0x8312, 0xf0},
+ {0x8313, 0xa4},
+ {0x8314, 0x2c},
+ {0x8315, 0xfc},
+ {0x8316, 0x8a},
+ {0x8317, 0xf0},
+ {0x8318, 0xed},
+ {0x8319, 0xa4},
+ {0x831a, 0x2c},
+ {0x831b, 0xfc},
+ {0x831c, 0xea},
+ {0x831d, 0x8e},
+ {0x831e, 0xf0},
+ {0x831f, 0xa4},
+ {0x8320, 0xcd},
+ {0x8321, 0xa8},
+ {0x8322, 0xf0},
+ {0x8323, 0x8b},
+ {0x8324, 0xf0},
+ {0x8325, 0xa4},
+ {0x8326, 0x2d},
+ {0x8327, 0xcc},
+ {0x8328, 0x38},
+ {0x8329, 0x25},
+ {0x832a, 0xf0},
+ {0x832b, 0xfd},
+ {0x832c, 0xe9},
+ {0x832d, 0x8f},
+ {0x832e, 0xf0},
+ {0x832f, 0xa4},
+ {0x8330, 0x2c},
+ {0x8331, 0xcd},
+ {0x8332, 0x35},
+ {0x8333, 0xf0},
+ {0x8334, 0xfc},
+ {0x8335, 0xeb},
+ {0x8336, 0x8e},
+ {0x8337, 0xf0},
+ {0x8338, 0xa4},
+ {0x8339, 0xfe},
+ {0x833a, 0xa9},
+ {0x833b, 0xf0},
+ {0x833c, 0xeb},
+ {0x833d, 0x8f},
+ {0x833e, 0xf0},
+ {0x833f, 0xa4},
+ {0x8340, 0xcf},
+ {0x8341, 0xc5},
+ {0x8342, 0xf0},
+ {0x8343, 0x2e},
+ {0x8344, 0xcd},
+ {0x8345, 0x39},
+ {0x8346, 0xfe},
+ {0x8347, 0xe4},
+ {0x8348, 0x3c},
+ {0x8349, 0xfc},
+ {0x834a, 0xea},
+ {0x834b, 0xa4},
+ {0x834c, 0x2d},
+ {0x834d, 0xce},
+ {0x834e, 0x35},
+ {0x834f, 0xf0},
+ {0x8350, 0xfd},
+ {0x8351, 0xe4},
+ {0x8352, 0x3c},
+ {0x8353, 0xfc},
+ {0x8354, 0x22},
+ {0x8355, 0x75},
+ {0x8356, 0xf0},
+ {0x8357, 0x08},
+ {0x8358, 0x75},
+ {0x8359, 0x82},
+ {0x835a, 0x00},
+ {0x835b, 0xef},
+ {0x835c, 0x2f},
+ {0x835d, 0xff},
+ {0x835e, 0xee},
+ {0x835f, 0x33},
+ {0x8360, 0xfe},
+ {0x8361, 0xcd},
+ {0x8362, 0x33},
+ {0x8363, 0xcd},
+ {0x8364, 0xcc},
+ {0x8365, 0x33},
+ {0x8366, 0xcc},
+ {0x8367, 0xc5},
+ {0x8368, 0x82},
+ {0x8369, 0x33},
+ {0x836a, 0xc5},
+ {0x836b, 0x82},
+ {0x836c, 0x9b},
+ {0x836d, 0xed},
+ {0x836e, 0x9a},
+ {0x836f, 0xec},
+ {0x8370, 0x99},
+ {0x8371, 0xe5},
+ {0x8372, 0x82},
+ {0x8373, 0x98},
+ {0x8374, 0x40},
+ {0x8375, 0x0c},
+ {0x8376, 0xf5},
+ {0x8377, 0x82},
+ {0x8378, 0xee},
+ {0x8379, 0x9b},
+ {0x837a, 0xfe},
+ {0x837b, 0xed},
+ {0x837c, 0x9a},
+ {0x837d, 0xfd},
+ {0x837e, 0xec},
+ {0x837f, 0x99},
+ {0x8380, 0xfc},
+ {0x8381, 0x0f},
+ {0x8382, 0xd5},
+ {0x8383, 0xf0},
+ {0x8384, 0xd6},
+ {0x8385, 0xe4},
+ {0x8386, 0xce},
+ {0x8387, 0xfb},
+ {0x8388, 0xe4},
+ {0x8389, 0xcd},
+ {0x838a, 0xfa},
+ {0x838b, 0xe4},
+ {0x838c, 0xcc},
+ {0x838d, 0xf9},
+ {0x838e, 0xa8},
+ {0x838f, 0x82},
+ {0x8390, 0x22},
+ {0x8391, 0xb8},
+ {0x8392, 0x00},
+ {0x8393, 0xc1},
+ {0x8394, 0xb9},
+ {0x8395, 0x00},
+ {0x8396, 0x59},
+ {0x8397, 0xba},
+ {0x8398, 0x00},
+ {0x8399, 0x2d},
+ {0x839a, 0xec},
+ {0x839b, 0x8b},
+ {0x839c, 0xf0},
+ {0x839d, 0x84},
+ {0x839e, 0xcf},
+ {0x839f, 0xce},
+ {0x83a0, 0xcd},
+ {0x83a1, 0xfc},
+ {0x83a2, 0xe5},
+ {0x83a3, 0xf0},
+ {0x83a4, 0xcb},
+ {0x83a5, 0xf9},
+ {0x83a6, 0x78},
+ {0x83a7, 0x18},
+ {0x83a8, 0xef},
+ {0x83a9, 0x2f},
+ {0x83aa, 0xff},
+ {0x83ab, 0xee},
+ {0x83ac, 0x33},
+ {0x83ad, 0xfe},
+ {0x83ae, 0xed},
+ {0x83af, 0x33},
+ {0x83b0, 0xfd},
+ {0x83b1, 0xec},
+ {0x83b2, 0x33},
+ {0x83b3, 0xfc},
+ {0x83b4, 0xeb},
+ {0x83b5, 0x33},
+ {0x83b6, 0xfb},
+ {0x83b7, 0x10},
+ {0x83b8, 0xd7},
+ {0x83b9, 0x03},
+ {0x83ba, 0x99},
+ {0x83bb, 0x40},
+ {0x83bc, 0x04},
+ {0x83bd, 0xeb},
+ {0x83be, 0x99},
+ {0x83bf, 0xfb},
+ {0x83c0, 0x0f},
+ {0x83c1, 0xd8},
+ {0x83c2, 0xe5},
+ {0x83c3, 0xe4},
+ {0x83c4, 0xf9},
+ {0x83c5, 0xfa},
+ {0x83c6, 0x22},
+ {0x83c7, 0x78},
+ {0x83c8, 0x18},
+ {0x83c9, 0xef},
+ {0x83ca, 0x2f},
+ {0x83cb, 0xff},
+ {0x83cc, 0xee},
+ {0x83cd, 0x33},
+ {0x83ce, 0xfe},
+ {0x83cf, 0xed},
+ {0x83d0, 0x33},
+ {0x83d1, 0xfd},
+ {0x83d2, 0xec},
+ {0x83d3, 0x33},
+ {0x83d4, 0xfc},
+ {0x83d5, 0xc9},
+ {0x83d6, 0x33},
+ {0x83d7, 0xc9},
+ {0x83d8, 0x10},
+ {0x83d9, 0xd7},
+ {0x83da, 0x05},
+ {0x83db, 0x9b},
+ {0x83dc, 0xe9},
+ {0x83dd, 0x9a},
+ {0x83de, 0x40},
+
+ {0x83df, 0x07},
+ {0x83e0, 0xec},
+ {0x83e1, 0x9b},
+ {0x83e2, 0xfc},
+ {0x83e3, 0xe9},
+ {0x83e4, 0x9a},
+ {0x83e5, 0xf9},
+ {0x83e6, 0x0f},
+ {0x83e7, 0xd8},
+ {0x83e8, 0xe0},
+ {0x83e9, 0xe4},
+ {0x83ea, 0xc9},
+ {0x83eb, 0xfa},
+ {0x83ec, 0xe4},
+ {0x83ed, 0xcc},
+ {0x83ee, 0xfb},
+ {0x83ef, 0x22},
+ {0x83f0, 0x75},
+ {0x83f1, 0xf0},
+ {0x83f2, 0x10},
+ {0x83f3, 0xef},
+ {0x83f4, 0x2f},
+ {0x83f5, 0xff},
+ {0x83f6, 0xee},
+ {0x83f7, 0x33},
+ {0x83f8, 0xfe},
+ {0x83f9, 0xed},
+ {0x83fa, 0x33},
+ {0x83fb, 0xfd},
+ {0x83fc, 0xcc},
+ {0x83fd, 0x33},
+ {0x83fe, 0xcc},
+ {0x83ff, 0xc8},
+ {0x8400, 0x33},
+ {0x8401, 0xc8},
+ {0x8402, 0x10},
+ {0x8403, 0xd7},
+ {0x8404, 0x07},
+ {0x8405, 0x9b},
+ {0x8406, 0xec},
+ {0x8407, 0x9a},
+ {0x8408, 0xe8},
+ {0x8409, 0x99},
+ {0x840a, 0x40},
+ {0x840b, 0x0a},
+ {0x840c, 0xed},
+ {0x840d, 0x9b},
+ {0x840e, 0xfd},
+ {0x840f, 0xec},
+ {0x8410, 0x9a},
+ {0x8411, 0xfc},
+ {0x8412, 0xe8},
+ {0x8413, 0x99},
+ {0x8414, 0xf8},
+ {0x8415, 0x0f},
+ {0x8416, 0xd5},
+ {0x8417, 0xf0},
+ {0x8418, 0xda},
+ {0x8419, 0xe4},
+ {0x841a, 0xcd},
+ {0x841b, 0xfb},
+ {0x841c, 0xe4},
+ {0x841d, 0xcc},
+ {0x841e, 0xfa},
+ {0x841f, 0xe4},
+ {0x8420, 0xc8},
+ {0x8421, 0xf9},
+ {0x8422, 0x22},
+ {0x8423, 0xeb},
+ {0x8424, 0x9f},
+ {0x8425, 0xf5},
+ {0x8426, 0xf0},
+ {0x8427, 0xea},
+ {0x8428, 0x9e},
+ {0x8429, 0x42},
+ {0x842a, 0xf0},
+ {0x842b, 0xe9},
+ {0x842c, 0x9d},
+ {0x842d, 0x42},
+ {0x842e, 0xf0},
+ {0x842f, 0xe8},
+ {0x8430, 0x9c},
+ {0x8431, 0x45},
+ {0x8432, 0xf0},
+ {0x8433, 0x22},
+ {0x8434, 0xe8},
+ {0x8435, 0x60},
+ {0x8436, 0x0f},
+ {0x8437, 0xef},
+ {0x8438, 0xc3},
+ {0x8439, 0x33},
+ {0x843a, 0xff},
+ {0x843b, 0xee},
+ {0x843c, 0x33},
+ {0x843d, 0xfe},
+ {0x843e, 0xed},
+ {0x843f, 0x33},
+ {0x8440, 0xfd},
+ {0x8441, 0xec},
+ {0x8442, 0x33},
+ {0x8443, 0xfc},
+ {0x8444, 0xd8},
+ {0x8445, 0xf1},
+ {0x8446, 0x22},
+ {0x8447, 0xe4},
+ {0x8448, 0x93},
+ {0x8449, 0xfc},
+ {0x844a, 0x74},
+ {0x844b, 0x01},
+ {0x844c, 0x93},
+ {0x844d, 0xfd},
+ {0x844e, 0x74},
+ {0x844f, 0x02},
+ {0x8450, 0x93},
+ {0x8451, 0xfe},
+ {0x8452, 0x74},
+ {0x8453, 0x03},
+ {0x8454, 0x93},
+ {0x8455, 0xff},
+ {0x8456, 0x22},
+ {0x8457, 0xe6},
+ {0x8458, 0xfb},
+ {0x8459, 0x08},
+ {0x845a, 0xe6},
+ {0x845b, 0xf9},
+ {0x845c, 0x08},
+ {0x845d, 0xe6},
+ {0x845e, 0xfa},
+ {0x845f, 0x08},
+ {0x8460, 0xe6},
+ {0x8461, 0xcb},
+ {0x8462, 0xf8},
+ {0x8463, 0x22},
+ {0x8464, 0xec},
+ {0x8465, 0xf6},
+ {0x8466, 0x08},
+ {0x8467, 0xed},
+ {0x8468, 0xf6},
+ {0x8469, 0x08},
+ {0x846a, 0xee},
+ {0x846b, 0xf6},
+ {0x846c, 0x08},
+ {0x846d, 0xef},
+ {0x846e, 0xf6},
+ {0x846f, 0x22},
+ {0x8470, 0xd0},
+ {0x8471, 0x83},
+ {0x8472, 0xd0},
+ {0x8473, 0x82},
+ {0x8474, 0xe4},
+ {0x8475, 0x93},
+ {0x8476, 0xf6},
+ {0x8477, 0x08},
+ {0x8478, 0x74},
+ {0x8479, 0x01},
+ {0x847a, 0x93},
+ {0x847b, 0xf6},
+ {0x847c, 0x08},
+ {0x847d, 0x74},
+ {0x847e, 0x02},
+ {0x847f, 0x93},
+ {0x8480, 0xf6},
+ {0x8481, 0x08},
+ {0x8482, 0x74},
+ {0x8483, 0x03},
+ {0x8484, 0x93},
+ {0x8485, 0xf6},
+ {0x8486, 0x74},
+ {0x8487, 0x04},
+ {0x8488, 0x73},
+ {0x8489, 0xa4},
+ {0x848a, 0x25},
+ {0x848b, 0x82},
+ {0x848c, 0xf5},
+ {0x848d, 0x82},
+ {0x848e, 0xe5},
+ {0x848f, 0xf0},
+ {0x8490, 0x35},
+ {0x8491, 0x83},
+ {0x8492, 0xf5},
+ {0x8493, 0x83},
+ {0x8494, 0x22},
+ {0x8495, 0xd0},
+ {0x8496, 0x83},
+ {0x8497, 0xd0},
+ {0x8498, 0x82},
+ {0x8499, 0xf8},
+ {0x849a, 0xe4},
+ {0x849b, 0x93},
+ {0x849c, 0x70},
+ {0x849d, 0x12},
+ {0x849e, 0x74},
+ {0x849f, 0x01},
+ {0x84a0, 0x93},
+ {0x84a1, 0x70},
+ {0x84a2, 0x0d},
+ {0x84a3, 0xa3},
+ {0x84a4, 0xa3},
+ {0x84a5, 0x93},
+ {0x84a6, 0xf8},
+ {0x84a7, 0x74},
+ {0x84a8, 0x01},
+ {0x84a9, 0x93},
+ {0x84aa, 0xf5},
+ {0x84ab, 0x82},
+ {0x84ac, 0x88},
+ {0x84ad, 0x83},
+ {0x84ae, 0xe4},
+ {0x84af, 0x73},
+ {0x84b0, 0x74},
+ {0x84b1, 0x02},
+ {0x84b2, 0x93},
+ {0x84b3, 0x68},
+ {0x84b4, 0x60},
+ {0x84b5, 0xef},
+ {0x84b6, 0xa3},
+ {0x84b7, 0xa3},
+ {0x84b8, 0xa3},
+ {0x84b9, 0x80},
+ {0x84ba, 0xdf},
+ {0x84bb, 0x90},
+ {0x84bc, 0x38},
+ {0x84bd, 0x04},
+ {0x84be, 0x78},
+ {0x84bf, 0x45},
+ {0x84c0, 0x12},
+ {0x84c1, 0x09},
+ {0x84c2, 0x1f},
+ {0x84c3, 0x90},
+ {0x84c4, 0x38},
+ {0x84c5, 0x00},
+ {0x84c6, 0xe0},
+ {0x84c7, 0xfe},
+ {0x84c8, 0xa3},
+ {0x84c9, 0xe0},
+ {0x84ca, 0xfd},
+ {0x84cb, 0xed},
+ {0x84cc, 0xff},
+ {0x84cd, 0xc3},
+ {0x84ce, 0x12},
+ {0x84cf, 0x08},
+ {0x84d0, 0xcb},
+ {0x84d1, 0x90},
+ {0x84d2, 0x38},
+ {0x84d3, 0x10},
+ {0x84d4, 0x12},
+ {0x84d5, 0x08},
+ {0x84d6, 0xbf},
+ {0x84d7, 0x90},
+ {0x84d8, 0x38},
+ {0x84d9, 0x06},
+ {0x84da, 0x78},
+ {0x84db, 0x47},
+ {0x84dc, 0x12},
+ {0x84dd, 0x09},
+ {0x84de, 0x1f},
+ {0x84df, 0x90},
+ {0x84e0, 0x38},
+ {0x84e1, 0x02},
+ {0x84e2, 0xe0},
+ {0x84e3, 0xfe},
+ {0x84e4, 0xa3},
+ {0x84e5, 0xe0},
+ {0x84e6, 0xfd},
+ {0x84e7, 0xed},
+ {0x84e8, 0xff},
+ {0x84e9, 0xc3},
+ {0x84ea, 0x12},
+ {0x84eb, 0x08},
+ {0x84ec, 0xcb},
+ {0x84ed, 0x90},
+ {0x84ee, 0x38},
+ {0x84ef, 0x12},
+ {0x84f0, 0x12},
+ {0x84f1, 0x08},
+ {0x84f2, 0xbf},
+ {0x84f3, 0xa3},
+ {0x84f4, 0xe0},
+ {0x84f5, 0xb4},
+ {0x84f6, 0x31},
+ {0x84f7, 0x07},
+ {0x84f8, 0x78},
+ {0x84f9, 0x45},
+ {0x84fa, 0x79},
+ {0x84fb, 0x45},
+ {0x84fc, 0x12},
+ {0x84fd, 0x09},
+ {0x84fe, 0x2a},
+ {0x84ff, 0x90},
+ {0x8500, 0x38},
+ {0x8501, 0x14},
+ {0x8502, 0xe0},
+ {0x8503, 0xb4},
+ {0x8504, 0x71},
+ {0x8505, 0x15},
+ {0x8506, 0x78},
+ {0x8507, 0x45},
+ {0x8508, 0xe6},
+ {0x8509, 0xfe},
+ {0x850a, 0x08},
+ {0x850b, 0xe6},
+ {0x850c, 0x78},
+ {0x850d, 0x02},
+ {0x850e, 0xce},
+ {0x850f, 0xc3},
+ {0x8510, 0x13},
+ {0x8511, 0xce},
+ {0x8512, 0x13},
+ {0x8513, 0xd8},
+ {0x8514, 0xf9},
+ {0x8515, 0x79},
+ {0x8516, 0x46},
+ {0x8517, 0xf7},
+ {0x8518, 0xee},
+ {0x8519, 0x19},
+ {0x851a, 0xf7},
+ {0x851b, 0x90},
+ {0x851c, 0x38},
+ {0x851d, 0x15},
+ {0x851e, 0xe0},
+ {0x851f, 0xb4},
+ {0x8520, 0x31},
+ {0x8521, 0x07},
+ {0x8522, 0x78},
+ {0x8523, 0x47},
+ {0x8524, 0x79},
+ {0x8525, 0x47},
+ {0x8526, 0x12},
+ {0x8527, 0x09},
+ {0x8528, 0x2a},
+ {0x8529, 0x90},
+ {0x852a, 0x38},
+ {0x852b, 0x15},
+ {0x852c, 0xe0},
+ {0x852d, 0xb4},
+ {0x852e, 0x71},
+ {0x852f, 0x15},
+ {0x8530, 0x78},
+ {0x8531, 0x47},
+ {0x8532, 0xe6},
+ {0x8533, 0xfe},
+ {0x8534, 0x08},
+ {0x8535, 0xe6},
+ {0x8536, 0x78},
+ {0x8537, 0x02},
+ {0x8538, 0xce},
+ {0x8539, 0xc3},
+ {0x853a, 0x13},
+ {0x853b, 0xce},
+ {0x853c, 0x13},
+ {0x853d, 0xd8},
+ {0x853e, 0xf9},
+ {0x853f, 0x79},
+ {0x8540, 0x48},
+ {0x8541, 0xf7},
+ {0x8542, 0xee},
+ {0x8543, 0x19},
+ {0x8544, 0xf7},
+ {0x8545, 0x79},
+ {0x8546, 0x45},
+ {0x8547, 0x12},
+ {0x8548, 0x08},
+ {0x8549, 0xfb},
+ {0x854a, 0x09},
+ {0x854b, 0x12},
+ {0x854c, 0x08},
+ {0x854d, 0xfb},
+ {0x854e, 0xaf},
+ {0x854f, 0x3a},
+ {0x8550, 0x12},
+ {0x8551, 0x08},
+ {0x8552, 0xb0},
+ {0x8553, 0x7d},
+ {0x8554, 0x50},
+ {0x8555, 0x12},
+ {0x8556, 0x02},
+ {0x8557, 0xb1},
+ {0x8558, 0x78},
+ {0x8559, 0x4d},
+ {0x855a, 0xa6},
+ {0x855b, 0x06},
+ {0x855c, 0x08},
+ {0x855d, 0xa6},
+ {0x855e, 0x07},
+ {0x855f, 0xaf},
+ {0x8560, 0x38},
+ {0x8561, 0x12},
+ {0x8562, 0x08},
+ {0x8563, 0xb0},
+ {0x8564, 0x7d},
+ {0x8565, 0x50},
+ {0x8566, 0x12},
+ {0x8567, 0x02},
+ {0x8568, 0xb1},
+ {0x8569, 0x78},
+ {0x856a, 0x49},
+ {0x856b, 0xa6},
+ {0x856c, 0x06},
+ {0x856d, 0x08},
+ {0x856e, 0xa6},
+ {0x856f, 0x07},
+ {0x8570, 0xaf},
+ {0x8571, 0x3b},
+ {0x8572, 0x78},
+ {0x8573, 0x47},
+ {0x8574, 0x12},
+ {0x8575, 0x08},
+ {0x8576, 0xb2},
+ {0x8577, 0x7d},
+ {0x8578, 0x3c},
+ {0x8579, 0x12},
+ {0x857a, 0x02},
+ {0x857b, 0xb1},
+ {0x857c, 0x78},
+ {0x857d, 0x4f},
+ {0x857e, 0xa6},
+ {0x857f, 0x06},
+ {0x8580, 0x08},
+ {0x8581, 0xa6},
+ {0x8582, 0x07},
+ {0x8583, 0xaf},
+ {0x8584, 0x39},
+ {0x8585, 0x7e},
+ {0x8586, 0x00},
+ {0x8587, 0x78},
+ {0x8588, 0x47},
+ {0x8589, 0x12},
+ {0x858a, 0x08},
+ {0x858b, 0xb4},
+ {0x858c, 0x7d},
+ {0x858d, 0x3c},
+ {0x858e, 0x12},
+ {0x858f, 0x02},
+ {0x8590, 0xb1},
+ {0x8591, 0x78},
+ {0x8592, 0x4b},
+ {0x8593, 0xa6},
+ {0x8594, 0x06},
+ {0x8595, 0x08},
+ {0x8596, 0xa6},
+ {0x8597, 0x07},
+ {0x8598, 0xc3},
+ {0x8599, 0x78},
+ {0x859a, 0x4e},
+ {0x859b, 0xe6},
+ {0x859c, 0x94},
+ {0x859d, 0x08},
+ {0x859e, 0x18},
+ {0x859f, 0xe6},
+ {0x85a0, 0x94},
+ {0x85a1, 0x00},
+ {0x85a2, 0x50},
+ {0x85a3, 0x05},
+ {0x85a4, 0x76},
+ {0x85a5, 0x00},
+ {0x85a6, 0x08},
+ {0x85a7, 0x76},
+ {0x85a8, 0x08},
+ {0x85a9, 0xc3},
+ {0x85aa, 0x78},
+ {0x85ab, 0x50},
+ {0x85ac, 0xe6},
+ {0x85ad, 0x94},
+ {0x85ae, 0x08},
+ {0x85af, 0x18},
+ {0x85b0, 0xe6},
+ {0x85b1, 0x94},
+ {0x85b2, 0x00},
+ {0x85b3, 0x50},
+ {0x85b4, 0x05},
+ {0x85b5, 0x76},
+ {0x85b6, 0x00},
+ {0x85b7, 0x08},
+ {0x85b8, 0x76},
+ {0x85b9, 0x08},
+ {0x85ba, 0x78},
+ {0x85bb, 0x4d},
+ {0x85bc, 0x12},
+ {0x85bd, 0x08},
+ {0x85be, 0xe8},
+ {0x85bf, 0xff},
+ {0x85c0, 0xc3},
+ {0x85c1, 0x78},
+ {0x85c2, 0x4a},
+ {0x85c3, 0xe6},
+ {0x85c4, 0x9f},
+ {0x85c5, 0xff},
+ {0x85c6, 0x18},
+ {0x85c7, 0xe6},
+ {0x85c8, 0x9e},
+ {0x85c9, 0x78},
+ {0x85ca, 0x51},
+ {0x85cb, 0x12},
+ {0x85cc, 0x08},
+ {0x85cd, 0xdf},
+ {0x85ce, 0xff},
+ {0x85cf, 0xc3},
+ {0x85d0, 0x78},
+ {0x85d1, 0x4c},
+ {0x85d2, 0xe6},
+ {0x85d3, 0x9f},
+ {0x85d4, 0xff},
+ {0x85d5, 0x18},
+ {0x85d6, 0xe6},
+ {0x85d7, 0x9e},
+ {0x85d8, 0xfe},
+ {0x85d9, 0xe4},
+ {0x85da, 0xfc},
+ {0x85db, 0xfd},
+ {0x85dc, 0x78},
+ {0x85dd, 0x55},
+ {0x85de, 0x12},
+ {0x85df, 0x04},
+ {0x85e0, 0x64},
+ {0x85e1, 0x78},
+ {0x85e2, 0x4d},
+ {0x85e3, 0x12},
+ {0x85e4, 0x08},
+ {0x85e5, 0xe8},
+ {0x85e6, 0x78},
+ {0x85e7, 0x4a},
+ {0x85e8, 0x26},
+ {0x85e9, 0xff},
+ {0x85ea, 0xee},
+ {0x85eb, 0x18},
+ {0x85ec, 0x36},
+ {0x85ed, 0x78},
+ {0x85ee, 0x59},
+ {0x85ef, 0x12},
+ {0x85f0, 0x08},
+ {0x85f1, 0xdf},
+ {0x85f2, 0x78},
+ {0x85f3, 0x4c},
+ {0x85f4, 0x26},
+ {0x85f5, 0xff},
+ {0x85f6, 0xee},
+ {0x85f7, 0x18},
+ {0x85f8, 0x36},
+ {0x85f9, 0xfe},
+ {0x85fa, 0xe4},
+ {0x85fb, 0xfc},
+ {0x85fc, 0xfd},
+ {0x85fd, 0x78},
+ {0x85fe, 0x5d},
+ {0x85ff, 0x12},
+ {0x8600, 0x04},
+ {0x8601, 0x64},
+ {0x8602, 0x78},
+ {0x8603, 0x51},
+ {0x8604, 0x12},
+ {0x8605, 0x09},
+ {0x8606, 0x13},
+ {0x8607, 0x50},
+ {0x8608, 0x09},
+ {0x8609, 0x78},
+ {0x860a, 0x51},
+ {0x860b, 0x12},
+ {0x860c, 0x04},
+ {0x860d, 0x70},
+ {0x860e, 0x00},
+ {0x860f, 0x00},
+ {0x8610, 0x00},
+ {0x8611, 0x00},
+ {0x8612, 0x78},
+ {0x8613, 0x55},
+ {0x8614, 0x12},
+ {0x8615, 0x09},
+ {0x8616, 0x13},
+ {0x8617, 0x50},
+ {0x8618, 0x09},
+ {0x8619, 0x78},
+ {0x861a, 0x55},
+ {0x861b, 0x12},
+ {0x861c, 0x04},
+ {0x861d, 0x70},
+ {0x861e, 0x00},
+ {0x861f, 0x00},
+ {0x8620, 0x00},
+ {0x8621, 0x00},
+ {0x8622, 0x12},
+ {0x8623, 0x08},
+ {0x8624, 0xf0},
+ {0x8625, 0x78},
+ {0x8626, 0x59},
+ {0x8627, 0x12},
+ {0x8628, 0x04},
+ {0x8629, 0x57},
+ {0x862a, 0xd3},
+ {0x862b, 0x12},
+ {0x862c, 0x04},
+ {0x862d, 0x23},
+ {0x862e, 0x40},
+ {0x862f, 0x08},
+ {0x8630, 0x12},
+ {0x8631, 0x08},
+ {0x8632, 0xf0},
+ {0x8633, 0x78},
+ {0x8634, 0x59},
+ {0x8635, 0x12},
+ {0x8636, 0x04},
+ {0x8637, 0x64},
+ {0x8638, 0x78},
+ {0x8639, 0x47},
+ {0x863a, 0x12},
+ {0x863b, 0x08},
+ {0x863c, 0xf2},
+ {0x863d, 0x78},
+ {0x863e, 0x5d},
+ {0x863f, 0x12},
+ {0x8640, 0x04},
+ {0x8641, 0x57},
+ {0x8642, 0xd3},
+ {0x8643, 0x12},
+ {0x8644, 0x04},
+ {0x8645, 0x23},
+ {0x8646, 0x40},
+ {0x8647, 0x0a},
+ {0x8648, 0x78},
+ {0x8649, 0x47},
+ {0x864a, 0x12},
+ {0x864b, 0x08},
+ {0x864c, 0xf2},
+ {0x864d, 0x78},
+ {0x864e, 0x5d},
+ {0x864f, 0x12},
+ {0x8650, 0x04},
+ {0x8651, 0x64},
+ {0x8652, 0xe4},
+ {0x8653, 0xfd},
+ {0x8654, 0x78},
+ {0x8655, 0x54},
+ {0x8656, 0x12},
+ {0x8657, 0x09},
+ {0x8658, 0x0b},
+ {0x8659, 0x24},
+ {0x865a, 0x01},
+ {0x865b, 0x12},
+ {0x865c, 0x08},
+ {0x865d, 0xd3},
+ {0x865e, 0x78},
+ {0x865f, 0x58},
+ {0x8660, 0x12},
+ {0x8661, 0x09},
+ {0x8662, 0x0b},
+ {0x8663, 0x24},
+ {0x8664, 0x02},
+ {0x8665, 0x12},
+ {0x8666, 0x08},
+ {0x8667, 0xd3},
+ {0x8668, 0x78},
+ {0x8669, 0x5c},
+ {0x866a, 0x12},
+ {0x866b, 0x09},
+ {0x866c, 0x0b},
+ {0x866d, 0x24},
+ {0x866e, 0x03},
+ {0x866f, 0x12},
+ {0x8670, 0x08},
+ {0x8671, 0xd3},
+ {0x8672, 0x78},
+ {0x8673, 0x60},
+ {0x8674, 0x12},
+ {0x8675, 0x09},
+ {0x8676, 0x0b},
+ {0x8677, 0x24},
+ {0x8678, 0x04},
+ {0x8679, 0x12},
+ {0x867a, 0x08},
+ {0x867b, 0xd3},
+ {0x867c, 0x0d},
+ {0x867d, 0xbd},
+ {0x867e, 0x05},
+ {0x867f, 0xd4},
+ {0x8680, 0xc2},
+ {0x8681, 0x0e},
+ {0x8682, 0xc2},
+ {0x8683, 0x06},
+ {0x8684, 0x22},
+ {0x8685, 0x85},
+ {0x8686, 0x08},
+ {0x8687, 0x36},
+ {0x8688, 0x90},
+ {0x8689, 0x30},
+ {0x868a, 0x24},
+ {0x868b, 0xe0},
+ {0x868c, 0xf5},
+ {0x868d, 0x32},
+ {0x868e, 0xa3},
+ {0x868f, 0xe0},
+ {0x8690, 0xf5},
+ {0x8691, 0x33},
+ {0x8692, 0xa3},
+ {0x8693, 0xe0},
+ {0x8694, 0xf5},
+ {0x8695, 0x34},
+ {0x8696, 0xa3},
+ {0x8697, 0xe0},
+ {0x8698, 0xf5},
+ {0x8699, 0x35},
+ {0x869a, 0xa3},
+ {0x869b, 0xe0},
+ {0x869c, 0xf5},
+ {0x869d, 0x31},
+ {0x869e, 0xd2},
+ {0x869f, 0x33},
+ {0x86a0, 0xe5},
+ {0x86a1, 0x36},
+ {0x86a2, 0x12},
+ {0x86a3, 0x04},
+ {0x86a4, 0x95},
+ {0x86a5, 0x06},
+ {0x86a6, 0xdf},
+ {0x86a7, 0x03},
+ {0x86a8, 0x06},
+ {0x86a9, 0xe3},
+ {0x86aa, 0x04},
+ {0x86ab, 0x06},
+ {0x86ac, 0xe9},
+ {0x86ad, 0x07},
+ {0x86ae, 0x06},
+ {0x86af, 0xf1},
+ {0x86b0, 0x08},
+ {0x86b1, 0x07},
+ {0x86b2, 0x14},
+ {0x86b3, 0x18},
+ {0x86b4, 0x07},
+ {0x86b5, 0x2a},
+ {0x86b6, 0x19},
+ {0x86b7, 0x07},
+ {0x86b8, 0x01},
+ {0x86b9, 0x1a},
+ {0x86ba, 0x07},
+ {0x86bb, 0x0c},
+ {0x86bc, 0x1b},
+ {0x86bd, 0x07},
+ {0x86be, 0x4e},
+ {0x86bf, 0x80},
+ {0x86c0, 0x07},
+ {0x86c1, 0x51},
+ {0x86c2, 0x81},
+ {0x86c3, 0x07},
+ {0x86c4, 0x6d},
+ {0x86c5, 0x8f},
+ {0x86c6, 0x07},
+ {0x86c7, 0x5c},
+ {0x86c8, 0x90},
+ {0x86c9, 0x07},
+ {0x86ca, 0x6d},
+ {0x86cb, 0x91},
+ {0x86cc, 0x07},
+ {0x86cd, 0x6d},
+ {0x86ce, 0x92},
+ {0x86cf, 0x07},
+ {0x86d0, 0x6d},
+ {0x86d1, 0x93},
+ {0x86d2, 0x07},
+ {0x86d3, 0x6d},
+ {0x86d4, 0x94},
+ {0x86d5, 0x07},
+ {0x86d6, 0x6d},
+ {0x86d7, 0x98},
+ {0x86d8, 0x07},
+ {0x86d9, 0x6a},
+ {0x86da, 0x9f},
+ {0x86db, 0x00},
+ {0x86dc, 0x00},
+ {0x86dd, 0x07},
+ {0x86de, 0x88},
+ {0x86df, 0x12},
+ {0x86e0, 0x0a},
+ {0x86e1, 0xb8},
+ {0x86e2, 0x22},
+ {0x86e3, 0x12},
+ {0x86e4, 0x0a},
+ {0x86e5, 0xb8},
+ {0x86e6, 0xd2},
+ {0x86e7, 0x03},
+ {0x86e8, 0x22},
+ {0x86e9, 0xa2},
+ {0x86ea, 0x36},
+ {0x86eb, 0xe4},
+ {0x86ec, 0x33},
+ {0x86ed, 0xf5},
+ {0x86ee, 0x31},
+ {0x86ef, 0x80},
+ {0x86f0, 0x7c},
+ {0x86f1, 0xc2},
+ {0x86f2, 0x01},
+ {0x86f3, 0xc2},
+ {0x86f4, 0x02},
+ {0x86f5, 0xc2},
+ {0x86f6, 0x03},
+ {0x86f7, 0x12},
+ {0x86f8, 0x09},
+ {0x86f9, 0x34},
+ {0x86fa, 0x75},
+ {0x86fb, 0x3f},
+ {0x86fc, 0x70},
+ {0x86fd, 0xd2},
+ {0x86fe, 0x34},
+ {0x86ff, 0x80},
+ {0x8700, 0x6c},
+ {0x8701, 0x85},
+ {0x8702, 0x35},
+ {0x8703, 0x3d},
+ {0x8704, 0x85},
+ {0x8705, 0x31},
+ {0x8706, 0x3e},
+ {0x8707, 0x12},
+ {0x8708, 0x08},
+ {0x8709, 0x1d},
+ {0x870a, 0x80},
+ {0x870b, 0x61},
+ {0x870c, 0x85},
+ {0x870d, 0x3d},
+ {0x870e, 0x35},
+ {0x870f, 0x85},
+ {0x8710, 0x3e},
+ {0x8711, 0x31},
+ {0x8712, 0x80},
+ {0x8713, 0x59},
+ {0x8714, 0xe4},
+ {0x8715, 0xf5},
+ {0x8716, 0x22},
+ {0x8717, 0xf5},
+ {0x8718, 0x23},
+ {0x8719, 0x85},
+ {0x871a, 0x35},
+ {0x871b, 0x1e},
+ {0x871c, 0x85},
+ {0x871d, 0x34},
+ {0x871e, 0x1d},
+ {0x871f, 0x85},
+ {0x8720, 0x33},
+ {0x8721, 0x1c},
+ {0x8722, 0x85},
+ {0x8723, 0x32},
+ {0x8724, 0x1b},
+ {0x8725, 0x12},
+ {0x8726, 0x0a},
+ {0x8727, 0x8a},
+ {0x8728, 0x80},
+ {0x8729, 0x1f},
+ {0x872a, 0x75},
+ {0x872b, 0x22},
+ {0x872c, 0x00},
+ {0x872d, 0x75},
+ {0x872e, 0x23},
+ {0x872f, 0x01},
+ {0x8730, 0x74},
+ {0x8731, 0xff},
+ {0x8732, 0xf5},
+ {0x8733, 0x1a},
+ {0x8734, 0xf5},
+ {0x8735, 0x19},
+ {0x8736, 0xf5},
+ {0x8737, 0x18},
+ {0x8738, 0xf5},
+ {0x8739, 0x17},
+ {0x873a, 0x12},
+ {0x873b, 0x0a},
+ {0x873c, 0x8a},
+ {0x873d, 0x85},
+ {0x873e, 0x1a},
+ {0x873f, 0x35},
+ {0x8740, 0x85},
+ {0x8741, 0x19},
+ {0x8742, 0x34},
+ {0x8743, 0x85},
+ {0x8744, 0x18},
+ {0x8745, 0x33},
+ {0x8746, 0x85},
+ {0x8747, 0x17},
+ {0x8748, 0x32},
+ {0x8749, 0xe4},
+ {0x874a, 0xf5},
+ {0x874b, 0x31},
+ {0x874c, 0x80},
+ {0x874d, 0x1f},
+ {0x874e, 0x02},
+ {0x874f, 0x0a},
+ {0x8750, 0xef},
+ {0x8751, 0x85},
+ {0x8752, 0x32},
+ {0x8753, 0x38},
+ {0x8754, 0x85},
+ {0x8755, 0x33},
+ {0x8756, 0x39},
+ {0x8757, 0x12},
+ {0x8758, 0x04},
+ {0x8759, 0xbb},
+ {0x875a, 0x80},
+ {0x875b, 0x11},
+ {0x875c, 0x85},
+ {0x875d, 0x35},
+ {0x875e, 0x3b},
+ {0x875f, 0x85},
+ {0x8760, 0x34},
+ {0x8761, 0x3a},
+ {0x8762, 0x85},
+ {0x8763, 0x33},
+ {0x8764, 0x39},
+ {0x8765, 0x85},
+ {0x8766, 0x32},
+ {0x8767, 0x38},
+ {0x8768, 0x80},
+ {0x8769, 0x03},
+ {0x876a, 0x02},
+ {0x876b, 0x04},
+ {0x876c, 0xbb},
+ {0x876d, 0x90},
+ {0x876e, 0x30},
+ {0x876f, 0x24},
+ {0x8770, 0xe5},
+ {0x8771, 0x32},
+ {0x8772, 0xf0},
+ {0x8773, 0xa3},
+ {0x8774, 0xe5},
+ {0x8775, 0x33},
+ {0x8776, 0xf0},
+ {0x8777, 0xa3},
+ {0x8778, 0xe5},
+ {0x8779, 0x34},
+ {0x877a, 0xf0},
+ {0x877b, 0xa3},
+ {0x877c, 0xe5},
+ {0x877d, 0x35},
+ {0x877e, 0xf0},
+ {0x877f, 0xa3},
+ {0x8780, 0xe5},
+ {0x8781, 0x31},
+ {0x8782, 0xf0},
+ {0x8783, 0x90},
+ {0x8784, 0x30},
+ {0x8785, 0x23},
+ {0x8786, 0xe4},
+ {0x8787, 0xf0},
+ {0x8788, 0x22},
+ {0x8789, 0xc0},
+ {0x878a, 0xe0},
+ {0x878b, 0xc0},
+ {0x878c, 0x83},
+ {0x878d, 0xc0},
+ {0x878e, 0x82},
+ {0x878f, 0xc0},
+ {0x8790, 0xd0},
+ {0x8791, 0x90},
+ {0x8792, 0x3f},
+ {0x8793, 0x0c},
+ {0x8794, 0xe0},
+ {0x8795, 0xf5},
+ {0x8796, 0x27},
+ {0x8797, 0xe5},
+ {0x8798, 0x27},
+ {0x8799, 0x30},
+ {0x879a, 0xe3},
+ {0x879b, 0x42},
+ {0x879c, 0x30},
+ {0x879d, 0x35},
+ {0x879e, 0x34},
+ {0x879f, 0x90},
+ {0x87a0, 0x60},
+ {0x87a1, 0x19},
+ {0x87a2, 0xe0},
+ {0x87a3, 0xf5},
+ {0x87a4, 0x0a},
+ {0x87a5, 0xa3},
+ {0x87a6, 0xe0},
+ {0x87a7, 0xf5},
+ {0x87a8, 0x0b},
+ {0x87a9, 0x30},
+ {0x87aa, 0x01},
+ {0x87ab, 0x06},
+ {0x87ac, 0x30},
+ {0x87ad, 0x32},
+ {0x87ae, 0x03},
+ {0x87af, 0xd3},
+ {0x87b0, 0x80},
+ {0x87b1, 0x01},
+ {0x87b2, 0xc3},
+ {0x87b3, 0x92},
+ {0x87b4, 0x09},
+ {0x87b5, 0x30},
+ {0x87b6, 0x02},
+ {0x87b7, 0x06},
+ {0x87b8, 0x30},
+ {0x87b9, 0x32},
+ {0x87ba, 0x03},
+ {0x87bb, 0xd3},
+ {0x87bc, 0x80},
+ {0x87bd, 0x01},
+ {0x87be, 0xc3},
+ {0x87bf, 0x92},
+ {0x87c0, 0x0a},
+ {0x87c1, 0x30},
+ {0x87c2, 0x32},
+ {0x87c3, 0x0c},
+ {0x87c4, 0x30},
+ {0x87c5, 0x03},
+ {0x87c6, 0x09},
+ {0x87c7, 0x20},
+ {0x87c8, 0x02},
+ {0x87c9, 0x06},
+ {0x87ca, 0x20},
+ {0x87cb, 0x01},
+ {0x87cc, 0x03},
+ {0x87cd, 0xd3},
+ {0x87ce, 0x80},
+ {0x87cf, 0x01},
+ {0x87d0, 0xc3},
+ {0x87d1, 0x92},
+ {0x87d2, 0x0b},
+ {0x87d3, 0x90},
+ {0x87d4, 0x30},
+ {0x87d5, 0x01},
+ {0x87d6, 0xe0},
+ {0x87d7, 0x44},
+ {0x87d8, 0x40},
+ {0x87d9, 0xf0},
+ {0x87da, 0xe0},
+ {0x87db, 0x54},
+ {0x87dc, 0xbf},
+ {0x87dd, 0xf0},
+ {0x87de, 0xe5},
+ {0x87df, 0x27},
+ {0x87e0, 0x30},
+ {0x87e1, 0xe1},
+ {0x87e2, 0x14},
+ {0x87e3, 0x30},
+ {0x87e4, 0x33},
+ {0x87e5, 0x11},
+ {0x87e6, 0x90},
+ {0x87e7, 0x30},
+ {0x87e8, 0x22},
+ {0x87e9, 0xe0},
+ {0x87ea, 0xf5},
+ {0x87eb, 0x08},
+ {0x87ec, 0xe4},
+ {0x87ed, 0xf0},
+ {0x87ee, 0x30},
+ {0x87ef, 0x00},
+ {0x87f0, 0x03},
+ {0x87f1, 0xd3},
+ {0x87f2, 0x80},
+ {0x87f3, 0x01},
+ {0x87f4, 0xc3},
+ {0x87f5, 0x92},
+ {0x87f6, 0x08},
+ {0x87f7, 0xe5},
+ {0x87f8, 0x27},
+ {0x87f9, 0x30},
+ {0x87fa, 0xe5},
+ {0x87fb, 0x12},
+ {0x87fc, 0x90},
+ {0x87fd, 0x56},
+ {0x87fe, 0x90},
+ {0x87ff, 0xe0},
+ {0x8800, 0xf5},
+ {0x8801, 0x09},
+ {0x8802, 0x30},
+ {0x8803, 0x30},
+ {0x8804, 0x09},
+ {0x8805, 0x30},
+ {0x8806, 0x05},
+ {0x8807, 0x03},
+ {0x8808, 0xd3},
+ {0x8809, 0x80},
+ {0x880a, 0x01},
+ {0x880b, 0xc3},
+ {0x880c, 0x92},
+ {0x880d, 0x0d},
+ {0x880e, 0x90},
+ {0x880f, 0x3f},
+ {0x8810, 0x0c},
+ {0x8811, 0xe5},
+ {0x8812, 0x27},
+ {0x8813, 0xf0},
+ {0x8814, 0xd0},
+ {0x8815, 0xd0},
+ {0x8816, 0xd0},
+ {0x8817, 0x82},
+ {0x8818, 0xd0},
+ {0x8819, 0x83},
+ {0x881a, 0xd0},
+ {0x881b, 0xe0},
+ {0x881c, 0x32},
+ {0x881d, 0x90},
+ {0x881e, 0x0e},
+ {0x881f, 0x7d},
+ {0x8820, 0xe4},
+ {0x8821, 0x93},
+ {0x8822, 0xfe},
+ {0x8823, 0x74},
+ {0x8824, 0x01},
+ {0x8825, 0x93},
+ {0x8826, 0xff},
+ {0x8827, 0xc3},
+ {0x8828, 0x90},
+ {0x8829, 0x0e},
+ {0x882a, 0x7b},
+ {0x882b, 0x74},
+ {0x882c, 0x01},
+ {0x882d, 0x93},
+ {0x882e, 0x9f},
+ {0x882f, 0xff},
+ {0x8830, 0xe4},
+ {0x8831, 0x93},
+ {0x8832, 0x9e},
+ {0x8833, 0xfe},
+ {0x8834, 0xe4},
+ {0x8835, 0x8f},
+ {0x8836, 0x30},
+ {0x8837, 0x8e},
+ {0x8838, 0x2f},
+ {0x8839, 0xf5},
+ {0x883a, 0x2e},
+ {0x883b, 0xf5},
+ {0x883c, 0x2d},
+ {0x883d, 0xab},
+ {0x883e, 0x30},
+ {0x883f, 0xaa},
+ {0x8840, 0x2f},
+ {0x8841, 0xa9},
+ {0x8842, 0x2e},
+ {0x8843, 0xa8},
+ {0x8844, 0x2d},
+ {0x8845, 0xaf},
+ {0x8846, 0x3e},
+ {0x8847, 0xfc},
+ {0x8848, 0xfd},
+ {0x8849, 0xfe},
+ {0x884a, 0x12},
+ {0x884b, 0x03},
+ {0x884c, 0x06},
+ {0x884d, 0x12},
+ {0x884e, 0x0a},
+ {0x884f, 0xd4},
+ {0x8850, 0xe4},
+ {0x8851, 0x7b},
+ {0x8852, 0xff},
+ {0x8853, 0xfa},
+ {0x8854, 0xf9},
+ {0x8855, 0xf8},
+ {0x8856, 0x12},
+ {0x8857, 0x03},
+ {0x8858, 0x91},
+ {0x8859, 0x12},
+ {0x885a, 0x0a},
+ {0x885b, 0xd4},
+ {0x885c, 0x90},
+ {0x885d, 0x0e},
+ {0x885e, 0x69},
+ {0x885f, 0xe4},
+ {0x8860, 0x12},
+ {0x8861, 0x0a},
+ {0x8862, 0xe9},
+ {0x8863, 0x12},
+ {0x8864, 0x0a},
+ {0x8865, 0xd4},
+ {0x8866, 0xe4},
+ {0x8867, 0x85},
+ {0x8868, 0x3d},
+ {0x8869, 0x2c},
+ {0x886a, 0xf5},
+ {0x886b, 0x2b},
+ {0x886c, 0xf5},
+ {0x886d, 0x2a},
+ {0x886e, 0xf5},
+ {0x886f, 0x29},
+ {0x8870, 0xaf},
+ {0x8871, 0x2c},
+ {0x8872, 0xae},
+ {0x8873, 0x2b},
+ {0x8874, 0xad},
+ {0x8875, 0x2a},
+ {0x8876, 0xac},
+ {0x8877, 0x29},
+ {0x8878, 0xa3},
+ {0x8879, 0x12},
+ {0x887a, 0x0a},
+ {0x887b, 0xe9},
+ {0x887c, 0x8f},
+ {0x887d, 0x2c},
+ {0x887e, 0x8e},
+ {0x887f, 0x2b},
+ {0x8880, 0x8d},
+ {0x8881, 0x2a},
+ {0x8882, 0x8c},
+ {0x8883, 0x29},
+ {0x8884, 0xe5},
+ {0x8885, 0x30},
+ {0x8886, 0x45},
+ {0x8887, 0x2c},
+ {0x8888, 0xf5},
+ {0x8889, 0x30},
+ {0x888a, 0xe5},
+ {0x888b, 0x2f},
+ {0x888c, 0x45},
+ {0x888d, 0x2b},
+ {0x888e, 0xf5},
+ {0x888f, 0x2f},
+ {0x8890, 0xe5},
+ {0x8891, 0x2e},
+ {0x8892, 0x45},
+ {0x8893, 0x2a},
+ {0x8894, 0xf5},
+ {0x8895, 0x2e},
+ {0x8896, 0xe5},
+ {0x8897, 0x2d},
+ {0x8898, 0x45},
+ {0x8899, 0x29},
+ {0x889a, 0xf5},
+ {0x889b, 0x2d},
+ {0x889c, 0xe4},
+ {0x889d, 0xf5},
+ {0x889e, 0x22},
+ {0x889f, 0xf5},
+ {0x88a0, 0x23},
+ {0x88a1, 0x85},
+ {0x88a2, 0x30},
+ {0x88a3, 0x1e},
+ {0x88a4, 0x85},
+ {0x88a5, 0x2f},
+ {0x88a6, 0x1d},
+ {0x88a7, 0x85},
+ {0x88a8, 0x2e},
+ {0x88a9, 0x1c},
+ {0x88aa, 0x85},
+ {0x88ab, 0x2d},
+ {0x88ac, 0x1b},
+ {0x88ad, 0x02},
+ {0x88ae, 0x0a},
+ {0x88af, 0x8a},
+ {0x88b0, 0x78},
+ {0x88b1, 0x45},
+ {0x88b2, 0x7e},
+ {0x88b3, 0x00},
+ {0x88b4, 0xe6},
+ {0x88b5, 0xfc},
+ {0x88b6, 0x08},
+ {0x88b7, 0xe6},
+ {0x88b8, 0xfd},
+ {0x88b9, 0x12},
+ {0x88ba, 0x02},
+ {0x88bb, 0x9f},
+ {0x88bc, 0x7c},
+ {0x88bd, 0x00},
+ {0x88be, 0x22},
+ {0x88bf, 0xe0},
+ {0x88c0, 0xa3},
+ {0x88c1, 0xe0},
+ {0x88c2, 0x75},
+ {0x88c3, 0xf0},
+ {0x88c4, 0x02},
+ {0x88c5, 0xa4},
+ {0x88c6, 0xff},
+ {0x88c7, 0xae},
+ {0x88c8, 0xf0},
+ {0x88c9, 0xc3},
+ {0x88ca, 0x08},
+ {0x88cb, 0xe6},
+ {0x88cc, 0x9f},
+ {0x88cd, 0xf6},
+ {0x88ce, 0x18},
+ {0x88cf, 0xe6},
+ {0x88d0, 0x9e},
+ {0x88d1, 0xf6},
+ {0x88d2, 0x22},
+ {0x88d3, 0xff},
+ {0x88d4, 0xe5},
+ {0x88d5, 0xf0},
+ {0x88d6, 0x34},
+ {0x88d7, 0x60},
+ {0x88d8, 0x8f},
+ {0x88d9, 0x82},
+ {0x88da, 0xf5},
+ {0x88db, 0x83},
+ {0x88dc, 0xec},
+ {0x88dd, 0xf0},
+ {0x88de, 0x22},
+ {0x88df, 0xfe},
+ {0x88e0, 0xe4},
+ {0x88e1, 0xfc},
+ {0x88e2, 0xfd},
+ {0x88e3, 0x12},
+ {0x88e4, 0x04},
+ {0x88e5, 0x64},
+ {0x88e6, 0x78},
+ {0x88e7, 0x4f},
+ {0x88e8, 0xe6},
+ {0x88e9, 0xc3},
+ {0x88ea, 0x13},
+ {0x88eb, 0xfe},
+ {0x88ec, 0x08},
+ {0x88ed, 0xe6},
+ {0x88ee, 0x13},
+ {0x88ef, 0x22},
+ {0x88f0, 0x78},
+ {0x88f1, 0x45},
+ {0x88f2, 0xe6},
+ {0x88f3, 0xfe},
+ {0x88f4, 0x08},
+ {0x88f5, 0xe6},
+ {0x88f6, 0xff},
+ {0x88f7, 0xe4},
+ {0x88f8, 0xfc},
+ {0x88f9, 0xfd},
+ {0x88fa, 0x22},
+ {0x88fb, 0xe7},
+ {0x88fc, 0xc4},
+ {0x88fd, 0xf8},
+ {0x88fe, 0x54},
+ {0x88ff, 0xf0},
+ {0x8900, 0xc8},
+ {0x8901, 0x68},
+ {0x8902, 0xf7},
+ {0x8903, 0x09},
+ {0x8904, 0xe7},
+ {0x8905, 0xc4},
+ {0x8906, 0x54},
+ {0x8907, 0x0f},
+ {0x8908, 0x48},
+ {0x8909, 0xf7},
+ {0x890a, 0x22},
+ {0x890b, 0xe6},
+ {0x890c, 0xfc},
+ {0x890d, 0xed},
+ {0x890e, 0x75},
+ {0x890f, 0xf0},
+ {0x8910, 0x04},
+ {0x8911, 0xa4},
+ {0x8912, 0x22},
+ {0x8913, 0xe4},
+ {0x8914, 0xff},
+ {0x8915, 0xfe},
+ {0x8916, 0xfd},
+ {0x8917, 0xfc},
+ {0x8918, 0x12},
+ {0x8919, 0x04},
+ {0x891a, 0x57},
+ {0x891b, 0xc3},
+ {0x891c, 0x02},
+ {0x891d, 0x04},
+ {0x891e, 0x23},
+ {0x891f, 0xe0},
+ {0x8920, 0xfe},
+ {0x8921, 0xa3},
+ {0x8922, 0xe0},
+ {0x8923, 0xfd},
+ {0x8924, 0xee},
+ {0x8925, 0xf6},
+ {0x8926, 0xed},
+ {0x8927, 0x08},
+ {0x8928, 0xf6},
+ {0x8929, 0x22},
+ {0x892a, 0xe6},
+ {0x892b, 0xc3},
+ {0x892c, 0x13},
+ {0x892d, 0xf7},
+ {0x892e, 0x08},
+ {0x892f, 0xe6},
+ {0x8930, 0x13},
+ {0x8931, 0x09},
+ {0x8932, 0xf7},
+ {0x8933, 0x22},
+ {0x8934, 0xe4},
+ {0x8935, 0xf5},
+ {0x8936, 0x3e},
+ {0x8937, 0x90},
+ {0x8938, 0x0e},
+ {0x8939, 0x77},
+ {0x893a, 0x93},
+ {0x893b, 0xff},
+ {0x893c, 0xe4},
+ {0x893d, 0x8f},
+ {0x893e, 0x2c},
+ {0x893f, 0xf5},
+ {0x8940, 0x2b},
+ {0x8941, 0xf5},
+ {0x8942, 0x2a},
+ {0x8943, 0xf5},
+ {0x8944, 0x29},
+ {0x8945, 0xaf},
+ {0x8946, 0x2c},
+ {0x8947, 0xae},
+ {0x8948, 0x2b},
+ {0x8949, 0xad},
+ {0x894a, 0x2a},
+ {0x894b, 0xac},
+ {0x894c, 0x29},
+ {0x894d, 0x90},
+ {0x894e, 0x0e},
+ {0x894f, 0x6a},
+ {0x8950, 0x12},
+ {0x8951, 0x0a},
+ {0x8952, 0xe9},
+ {0x8953, 0x8f},
+ {0x8954, 0x2c},
+ {0x8955, 0x8e},
+ {0x8956, 0x2b},
+ {0x8957, 0x8d},
+ {0x8958, 0x2a},
+ {0x8959, 0x8c},
+ {0x895a, 0x29},
+ {0x895b, 0x90},
+ {0x895c, 0x0e},
+ {0x895d, 0x72},
+ {0x895e, 0x12},
+ {0x895f, 0x04},
+ {0x8960, 0x47},
+ {0x8961, 0xef},
+ {0x8962, 0x45},
+ {0x8963, 0x2c},
+ {0x8964, 0xf5},
+ {0x8965, 0x2c},
+ {0x8966, 0xee},
+ {0x8967, 0x45},
+ {0x8968, 0x2b},
+ {0x8969, 0xf5},
+ {0x896a, 0x2b},
+ {0x896b, 0xed},
+ {0x896c, 0x45},
+ {0x896d, 0x2a},
+ {0x896e, 0xf5},
+ {0x896f, 0x2a},
+ {0x8970, 0xec},
+ {0x8971, 0x45},
+ {0x8972, 0x29},
+ {0x8973, 0xf5},
+ {0x8974, 0x29},
+ {0x8975, 0xe4},
+ {0x8976, 0xf5},
+ {0x8977, 0x22},
+ {0x8978, 0xf5},
+ {0x8979, 0x23},
+ {0x897a, 0x85},
+ {0x897b, 0x2c},
+ {0x897c, 0x1e},
+ {0x897d, 0x85},
+ {0x897e, 0x2b},
+ {0x897f, 0x1d},
+ {0x8980, 0x85},
+ {0x8981, 0x2a},
+ {0x8982, 0x1c},
+ {0x8983, 0x85},
+ {0x8984, 0x29},
+ {0x8985, 0x1b},
+ {0x8986, 0x12},
+ {0x8987, 0x0a},
+ {0x8988, 0x8a},
+ {0x8989, 0xe4},
+ {0x898a, 0xf5},
+ {0x898b, 0x22},
+ {0x898c, 0xf5},
+ {0x898d, 0x23},
+ {0x898e, 0x90},
+ {0x898f, 0x0e},
+ {0x8990, 0x72},
+ {0x8991, 0x12},
+ {0x8992, 0x0a},
+ {0x8993, 0xdd},
+ {0x8994, 0x12},
+ {0x8995, 0x0a},
+ {0x8996, 0x8a},
+ {0x8997, 0xe4},
+ {0x8998, 0xf5},
+ {0x8999, 0x22},
+ {0x899a, 0xf5},
+ {0x899b, 0x23},
+ {0x899c, 0x90},
+ {0x899d, 0x0e},
+ {0x899e, 0x6e},
+ {0x899f, 0x12},
+ {0x89a0, 0x0a},
+ {0x89a1, 0xdd},
+ {0x89a2, 0x02},
+ {0x89a3, 0x0a},
+ {0x89a4, 0x8a},
+ {0x89a5, 0x75},
+ {0x89a6, 0x89},
+ {0x89a7, 0x03},
+ {0x89a8, 0x75},
+ {0x89a9, 0xa8},
+ {0x89aa, 0x01},
+ {0x89ab, 0x75},
+ {0x89ac, 0xb8},
+ {0x89ad, 0x04},
+ {0x89ae, 0x75},
+ {0x89af, 0x29},
+ {0x89b0, 0xff},
+ {0x89b1, 0x75},
+ {0x89b2, 0x2a},
+ {0x89b3, 0x0e},
+ {0x89b4, 0x75},
+ {0x89b5, 0x2b},
+ {0x89b6, 0x15},
+ {0x89b7, 0x75},
+ {0x89b8, 0x2c},
+ {0x89b9, 0x0d},
+ {0x89ba, 0x12},
+ {0x89bb, 0x0a},
+ {0x89bc, 0x0e},
+ {0x89bd, 0x12},
+ {0x89be, 0x00},
+ {0x89bf, 0x09},
+ {0x89c0, 0x12},
+ {0x89c1, 0x0a},
+ {0x89c2, 0xef},
+ {0x89c3, 0x12},
+ {0x89c4, 0x00},
+ {0x89c5, 0x06},
+ {0x89c6, 0xd2},
+ {0x89c7, 0x00},
+ {0x89c8, 0xd2},
+ {0x89c9, 0x33},
+ {0x89ca, 0xd2},
+ {0x89cb, 0xaf},
+ {0x89cc, 0x75},
+ {0x89cd, 0x29},
+ {0x89ce, 0xff},
+ {0x89cf, 0x75},
+ {0x89d0, 0x2a},
+ {0x89d1, 0x0e},
+ {0x89d2, 0x75},
+ {0x89d3, 0x2b},
+ {0x89d4, 0x49},
+ {0x89d5, 0x75},
+ {0x89d6, 0x2c},
+ {0x89d7, 0x03},
+ {0x89d8, 0x12},
+ {0x89d9, 0x0a},
+ {0x89da, 0x0e},
+ {0x89db, 0x30},
+ {0x89dc, 0x08},
+ {0x89dd, 0x09},
+ {0x89de, 0xc2},
+ {0x89df, 0x33},
+ {0x89e0, 0x12},
+ {0x89e1, 0x06},
+ {0x89e2, 0x85},
+ {0x89e3, 0xc2},
+ {0x89e4, 0x08},
+ {0x89e5, 0xd2},
+ {0x89e6, 0x33},
+ {0x89e7, 0x30},
+ {0x89e8, 0x09},
+ {0x89e9, 0x09},
+ {0x89ea, 0xc2},
+ {0x89eb, 0x35},
+ {0x89ec, 0x12},
+ {0x89ed, 0x00},
+ {0x89ee, 0x0e},
+ {0x89ef, 0xc2},
+ {0x89f0, 0x09},
+ {0x89f1, 0xd2},
+ {0x89f2, 0x35},
+ {0x89f3, 0x30},
+ {0x89f4, 0x0e},
+ {0x89f5, 0x03},
+ {0x89f6, 0x12},
+ {0x89f7, 0x04},
+ {0x89f8, 0xbb},
+ {0x89f9, 0x30},
+ {0x89fa, 0x34},
+ {0x89fb, 0xdf},
+ {0x89fc, 0x90},
+ {0x89fd, 0x30},
+ {0x89fe, 0x29},
+ {0x89ff, 0xe5},
+ {0x8a00, 0x3f},
+ {0x8a01, 0xf0},
+ {0x8a02, 0xb4},
+ {0x8a03, 0x10},
+ {0x8a04, 0x05},
+ {0x8a05, 0x90},
+ {0x8a06, 0x30},
+ {0x8a07, 0x23},
+ {0x8a08, 0xe4},
+ {0x8a09, 0xf0},
+ {0x8a0a, 0xc2},
+ {0x8a0b, 0x34},
+ {0x8a0c, 0x80},
+ {0x8a0d, 0xcd},
+ {0x8a0e, 0xae},
+ {0x8a0f, 0x2a},
+ {0x8a10, 0xaf},
+ {0x8a11, 0x2b},
+ {0x8a12, 0xe4},
+ {0x8a13, 0xfd},
+ {0x8a14, 0xed},
+ {0x8a15, 0xc3},
+ {0x8a16, 0x95},
+ {0x8a17, 0x2c},
+ {0x8a18, 0x50},
+ {0x8a19, 0x33},
+ {0x8a1a, 0x12},
+ {0x8a1b, 0x0b},
+ {0x8a1c, 0x36},
+ {0x8a1d, 0xe4},
+ {0x8a1e, 0x93},
+ {0x8a1f, 0xf5},
+ {0x8a20, 0x2d},
+ {0x8a21, 0x74},
+ {0x8a22, 0x01},
+ {0x8a23, 0x93},
+ {0x8a24, 0xf5},
+ {0x8a25, 0x2e},
+ {0x8a26, 0x45},
+ {0x8a27, 0x2d},
+ {0x8a28, 0x60},
+ {0x8a29, 0x23},
+ {0x8a2a, 0x85},
+ {0x8a2b, 0x2e},
+ {0x8a2c, 0x82},
+ {0x8a2d, 0x85},
+ {0x8a2e, 0x2d},
+ {0x8a2f, 0x83},
+ {0x8a30, 0xe0},
+ {0x8a31, 0xfc},
+ {0x8a32, 0x12},
+ {0x8a33, 0x0b},
+ {0x8a34, 0x36},
+ {0x8a35, 0x74},
+ {0x8a36, 0x03},
+ {0x8a37, 0x93},
+ {0x8a38, 0x52},
+ {0x8a39, 0x04},
+ {0x8a3a, 0x12},
+ {0x8a3b, 0x0b},
+ {0x8a3c, 0x36},
+ {0x8a3d, 0x74},
+ {0x8a3e, 0x02},
+ {0x8a3f, 0x93},
+ {0x8a40, 0x42},
+ {0x8a41, 0x04},
+ {0x8a42, 0x85},
+ {0x8a43, 0x2e},
+ {0x8a44, 0x82},
+ {0x8a45, 0x85},
+ {0x8a46, 0x2d},
+ {0x8a47, 0x83},
+ {0x8a48, 0xec},
+ {0x8a49, 0xf0},
+ {0x8a4a, 0x0d},
+ {0x8a4b, 0x80},
+ {0x8a4c, 0xc7},
+ {0x8a4d, 0x22},
+ {0x8a4e, 0x78},
+ {0x8a4f, 0xb1},
+ {0x8a50, 0xe6},
+ {0x8a51, 0xd3},
+ {0x8a52, 0x08},
+ {0x8a53, 0xff},
+ {0x8a54, 0xe6},
+ {0x8a55, 0x64},
+ {0x8a56, 0x80},
+ {0x8a57, 0xf8},
+ {0x8a58, 0xef},
+ {0x8a59, 0x64},
+ {0x8a5a, 0x80},
+ {0x8a5b, 0x98},
+ {0x8a5c, 0x22},
+ {0x8a5d, 0x93},
+ {0x8a5e, 0xff},
+ {0x8a5f, 0x7e},
+ {0x8a60, 0x00},
+ {0x8a61, 0xe6},
+ {0x8a62, 0xfc},
+ {0x8a63, 0x08},
+ {0x8a64, 0xe6},
+ {0x8a65, 0xfd},
+ {0x8a66, 0x12},
+ {0x8a67, 0x02},
+ {0x8a68, 0x9f},
+ {0x8a69, 0x78},
+ {0x8a6a, 0xb4},
+ {0x8a6b, 0xe6},
+ {0x8a6c, 0xfc},
+ {0x8a6d, 0x08},
+ {0x8a6e, 0xe6},
+ {0x8a6f, 0xfd},
+ {0x8a70, 0xd3},
+ {0x8a71, 0xef},
+ {0x8a72, 0x9d},
+ {0x8a73, 0xee},
+ {0x8a74, 0x9c},
+ {0x8a75, 0x22},
+ {0x8a76, 0x78},
+ {0x8a77, 0xb0},
+ {0x8a78, 0xd3},
+ {0x8a79, 0xe6},
+ {0x8a7a, 0x64},
+ {0x8a7b, 0x80},
+ {0x8a7c, 0x94},
+ {0x8a7d, 0x80},
+ {0x8a7e, 0x22},
+ {0x8a7f, 0x25},
+ {0x8a80, 0xe0},
+ {0x8a81, 0x24},
+ {0x8a82, 0x0a},
+ {0x8a83, 0xf8},
+ {0x8a84, 0xe6},
+ {0x8a85, 0xfe},
+ {0x8a86, 0x08},
+ {0x8a87, 0xe6},
+ {0x8a88, 0xff},
+ {0x8a89, 0x22},
+ {0x8a8a, 0xa2},
+ {0x8a8b, 0xaf},
+ {0x8a8c, 0x92},
+ {0x8a8d, 0x31},
+ {0x8a8e, 0xc2},
+ {0x8a8f, 0xaf},
+ {0x8a90, 0xe5},
+ {0x8a91, 0x23},
+ {0x8a92, 0x45},
+ {0x8a93, 0x22},
+ {0x8a94, 0x90},
+ {0x8a95, 0x0e},
+ {0x8a96, 0x5d},
+ {0x8a97, 0x60},
+ {0x8a98, 0x0b},
+ {0x8a99, 0x12},
+ {0x8a9a, 0x0b},
+ {0x8a9b, 0x2b},
+ {0x8a9c, 0xe0},
+ {0x8a9d, 0xf5},
+ {0x8a9e, 0x19},
+ {0x8a9f, 0xe0},
+ {0x8aa0, 0xf5},
+ {0x8aa1, 0x1a},
+ {0x8aa2, 0x80},
+ {0x8aa3, 0x0f},
+ {0x8aa4, 0x12},
+ {0x8aa5, 0x0b},
+ {0x8aa6, 0x2b},
+ {0x8aa7, 0xe5},
+ {0x8aa8, 0x1d},
+ {0x8aa9, 0xf0},
+ {0x8aaa, 0x90},
+ {0x8aab, 0x0e},
+ {0x8aac, 0x5f},
+ {0x8aad, 0x12},
+ {0x8aae, 0x0b},
+ {0x8aaf, 0x2b},
+ {0x8ab0, 0xe5},
+ {0x8ab1, 0x1e},
+ {0x8ab2, 0xf0},
+ {0x8ab3, 0xa2},
+ {0x8ab4, 0x31},
+ {0x8ab5, 0x92},
+ {0x8ab6, 0xaf},
+ {0x8ab7, 0x22},
+ {0x8ab8, 0xd2},
+ {0x8ab9, 0x01},
+ {0x8aba, 0xc2},
+ {0x8abb, 0x02},
+ {0x8abc, 0xe4},
+ {0x8abd, 0xf5},
+ {0x8abe, 0x40},
+ {0x8abf, 0xf5},
+ {0x8ac0, 0x3f},
+ {0x8ac1, 0xd2},
+ {0x8ac2, 0x34},
+ {0x8ac3, 0xd2},
+ {0x8ac4, 0x32},
+ {0x8ac5, 0xd2},
+ {0x8ac6, 0x35},
+ {0x8ac7, 0xd2},
+ {0x8ac8, 0x01},
+ {0x8ac9, 0xc2},
+ {0x8aca, 0x02},
+ {0x8acb, 0xf5},
+ {0x8acc, 0x40},
+ {0x8acd, 0xf5},
+ {0x8ace, 0x3f},
+ {0x8acf, 0xd2},
+ {0x8ad0, 0x34},
+ {0x8ad1, 0xd2},
+ {0x8ad2, 0x32},
+ {0x8ad3, 0x22},
+ {0x8ad4, 0x8f},
+ {0x8ad5, 0x30},
+ {0x8ad6, 0x8e},
+ {0x8ad7, 0x2f},
+ {0x8ad8, 0x8d},
+ {0x8ad9, 0x2e},
+ {0x8ada, 0x8c},
+ {0x8adb, 0x2d},
+ {0x8adc, 0x22},
+ {0x8add, 0x12},
+ {0x8ade, 0x04},
+ {0x8adf, 0x47},
+ {0x8ae0, 0x8f},
+ {0x8ae1, 0x1e},
+ {0x8ae2, 0x8e},
+ {0x8ae3, 0x1d},
+ {0x8ae4, 0x8d},
+ {0x8ae5, 0x1c},
+ {0x8ae6, 0x8c},
+ {0x8ae7, 0x1b},
+ {0x8ae8, 0x22},
+ {0x8ae9, 0x93},
+ {0x8aea, 0xf9},
+ {0x8aeb, 0xf8},
+ {0x8aec, 0x02},
+ {0x8aed, 0x04},
+ {0x8aee, 0x34},
+ {0x8aef, 0x90},
+ {0x8af0, 0x0e},
+ {0x8af1, 0x81},
+ {0x8af2, 0x12},
+ {0x8af3, 0x04},
+ {0x8af4, 0x47},
+ {0x8af5, 0x8f},
+ {0x8af6, 0x3b},
+ {0x8af7, 0x8e},
+ {0x8af8, 0x3a},
+ {0x8af9, 0x8d},
+ {0x8afa, 0x39},
+ {0x8afb, 0x8c},
+ {0x8afc, 0x38},
+ {0x8afd, 0xd2},
+ {0x8afe, 0x06},
+ {0x8aff, 0x30},
+ {0x8b00, 0x06},
+ {0x8b01, 0x03},
+ {0x8b02, 0xd3},
+ {0x8b03, 0x80},
+ {0x8b04, 0x01},
+ {0x8b05, 0xc3},
+ {0x8b06, 0x92},
+ {0x8b07, 0x0e},
+ {0x8b08, 0x22},
+ {0x8b09, 0xc0},
+ {0x8b0a, 0xe0},
+ {0x8b0b, 0xc0},
+ {0x8b0c, 0x83},
+ {0x8b0d, 0xc0},
+ {0x8b0e, 0x82},
+ {0x8b0f, 0x90},
+ {0x8b10, 0x3f},
+ {0x8b11, 0x0d},
+ {0x8b12, 0xe0},
+ {0x8b13, 0xf5},
+ {0x8b14, 0x28},
+ {0x8b15, 0xe5},
+ {0x8b16, 0x28},
+ {0x8b17, 0xf0},
+ {0x8b18, 0xd0},
+ {0x8b19, 0x82},
+ {0x8b1a, 0xd0},
+ {0x8b1b, 0x83},
+ {0x8b1c, 0xd0},
+ {0x8b1d, 0xe0},
+ {0x8b1e, 0x32},
+ {0x8b1f, 0x78},
+ {0x8b20, 0x7f},
+ {0x8b21, 0xe4},
+ {0x8b22, 0xf6},
+ {0x8b23, 0xd8},
+ {0x8b24, 0xfd},
+ {0x8b25, 0x75},
+ {0x8b26, 0x81},
+ {0x8b27, 0xc0},
+ {0x8b28, 0x02},
+ {0x8b29, 0x09},
+ {0x8b2a, 0xa5},
+ {0x8b2b, 0xe4},
+ {0x8b2c, 0x93},
+ {0x8b2d, 0xfe},
+ {0x8b2e, 0x74},
+ {0x8b2f, 0x01},
+ {0x8b30, 0x93},
+ {0x8b31, 0xf5},
+ {0x8b32, 0x82},
+ {0x8b33, 0x8e},
+ {0x8b34, 0x83},
+ {0x8b35, 0x22},
+ {0x8b36, 0x8f},
+ {0x8b37, 0x82},
+ {0x8b38, 0x8e},
+ {0x8b39, 0x83},
+ {0x8b3a, 0x75},
+ {0x8b3b, 0xf0},
+ {0x8b3c, 0x04},
+ {0x8b3d, 0xed},
+ {0x8b3e, 0x02},
+ {0x8b3f, 0x04},
+ {0x8b40, 0x89},
+ {0x8b41, 0x00},
+ {0x8b42, 0x00},
+ {0x8b43, 0x00},
+ {0x8b44, 0x00},
+ {0x8b45, 0x00},
+ {0x8b46, 0x00},
+ {0x8b47, 0x00},
+ {0x8b48, 0x00},
+ {0x8b49, 0x00},
+ {0x8b4a, 0x00},
+ {0x8b4b, 0x00},
+ {0x8b4c, 0x00},
+ {0x8b4d, 0x00},
+ {0x8b4e, 0x00},
+ {0x8b4f, 0x00},
+ {0x8b50, 0x00},
+ {0x8b51, 0x00},
+ {0x8b52, 0x00},
+ {0x8b53, 0x00},
+ {0x8b54, 0x00},
+ {0x8b55, 0x00},
+ {0x8b56, 0x00},
+ {0x8b57, 0x00},
+ {0x8b58, 0x00},
+ {0x8b59, 0x00},
+ {0x8b5a, 0x00},
+ {0x8b5b, 0x00},
+ {0x8b5c, 0x00},
+ {0x8b5d, 0x00},
+ {0x8b5e, 0x00},
+ {0x8b5f, 0x00},
+ {0x8b60, 0x00},
+ {0x8b61, 0x00},
+ {0x8b62, 0x00},
+ {0x8b63, 0x00},
+ {0x8b64, 0x00},
+ {0x8b65, 0x00},
+ {0x8b66, 0x00},
+ {0x8b67, 0x00},
+ {0x8b68, 0x00},
+ {0x8b69, 0x00},
+ {0x8b6a, 0x00},
+ {0x8b6b, 0x00},
+ {0x8b6c, 0x00},
+ {0x8b6d, 0x00},
+ {0x8b6e, 0x00},
+ {0x8b6f, 0x00},
+ {0x8b70, 0x00},
+ {0x8b71, 0x00},
+ {0x8b72, 0x00},
+ {0x8b73, 0x00},
+ {0x8b74, 0x00},
+ {0x8b75, 0x00},
+ {0x8b76, 0x00},
+ {0x8b77, 0x00},
+ {0x8b78, 0x00},
+ {0x8b79, 0x00},
+ {0x8b7a, 0x00},
+ {0x8b7b, 0x00},
+ {0x8b7c, 0x00},
+ {0x8b7d, 0x00},
+ {0x8b7e, 0x00},
+ {0x8b7f, 0x00},
+ {0x8b80, 0x00},
+ {0x8b81, 0x00},
+ {0x8b82, 0x00},
+ {0x8b83, 0x00},
+ {0x8b84, 0x00},
+ {0x8b85, 0x00},
+ {0x8b86, 0x00},
+ {0x8b87, 0x00},
+ {0x8b88, 0x00},
+ {0x8b89, 0x00},
+ {0x8b8a, 0x00},
+ {0x8b8b, 0x00},
+ {0x8b8c, 0x00},
+ {0x8b8d, 0x00},
+ {0x8b8e, 0x00},
+ {0x8b8f, 0x00},
+ {0x8b90, 0x00},
+ {0x8b91, 0x00},
+ {0x8b92, 0x00},
+ {0x8b93, 0x00},
+ {0x8b94, 0x00},
+ {0x8b95, 0x00},
+ {0x8b96, 0x00},
+ {0x8b97, 0x00},
+ {0x8b98, 0x00},
+ {0x8b99, 0x00},
+ {0x8b9a, 0x00},
+ {0x8b9b, 0x00},
+ {0x8b9c, 0x00},
+ {0x8b9d, 0x00},
+ {0x8b9e, 0x00},
+ {0x8b9f, 0x00},
+ {0x8ba0, 0x00},
+ {0x8ba1, 0x00},
+ {0x8ba2, 0x00},
+ {0x8ba3, 0x00},
+ {0x8ba4, 0x00},
+ {0x8ba5, 0x00},
+ {0x8ba6, 0x00},
+ {0x8ba7, 0x00},
+ {0x8ba8, 0x00},
+ {0x8ba9, 0x00},
+ {0x8baa, 0x00},
+ {0x8bab, 0x00},
+ {0x8bac, 0x00},
+ {0x8bad, 0x00},
+ {0x8bae, 0x00},
+ {0x8baf, 0x00},
+ {0x8bb0, 0x00},
+ {0x8bb1, 0x00},
+ {0x8bb2, 0x00},
+ {0x8bb3, 0x00},
+ {0x8bb4, 0x00},
+ {0x8bb5, 0x00},
+ {0x8bb6, 0x00},
+ {0x8bb7, 0x00},
+ {0x8bb8, 0x00},
+ {0x8bb9, 0x00},
+ {0x8bba, 0x00},
+ {0x8bbb, 0x00},
+ {0x8bbc, 0x00},
+ {0x8bbd, 0x00},
+ {0x8bbe, 0x00},
+ {0x8bbf, 0x00},
+ {0x8bc0, 0x00},
+ {0x8bc1, 0x00},
+ {0x8bc2, 0x00},
+ {0x8bc3, 0x00},
+ {0x8bc4, 0x00},
+ {0x8bc5, 0x00},
+ {0x8bc6, 0x00},
+ {0x8bc7, 0x00},
+ {0x8bc8, 0x00},
+ {0x8bc9, 0x00},
+ {0x8bca, 0x00},
+ {0x8bcb, 0x00},
+ {0x8bcc, 0x00},
+ {0x8bcd, 0x00},
+ {0x8bce, 0x00},
+ {0x8bcf, 0x00},
+ {0x8bd0, 0x00},
+ {0x8bd1, 0x00},
+ {0x8bd2, 0x00},
+ {0x8bd3, 0x00},
+ {0x8bd4, 0x00},
+ {0x8bd5, 0x00},
+ {0x8bd6, 0x00},
+ {0x8bd7, 0x00},
+ {0x8bd8, 0x00},
+ {0x8bd9, 0x00},
+ {0x8bda, 0x00},
+ {0x8bdb, 0x00},
+ {0x8bdc, 0x00},
+ {0x8bdd, 0x00},
+ {0x8bde, 0x00},
+ {0x8bdf, 0x00},
+ {0x8be0, 0x00},
+ {0x8be1, 0x00},
+ {0x8be2, 0x00},
+ {0x8be3, 0x00},
+ {0x8be4, 0x00},
+ {0x8be5, 0x00},
+ {0x8be6, 0x00},
+ {0x8be7, 0x00},
+ {0x8be8, 0x00},
+ {0x8be9, 0x00},
+ {0x8bea, 0x00},
+ {0x8beb, 0x00},
+ {0x8bec, 0x00},
+ {0x8bed, 0x00},
+ {0x8bee, 0x00},
+ {0x8bef, 0x00},
+ {0x8bf0, 0x00},
+ {0x8bf1, 0x00},
+ {0x8bf2, 0x00},
+ {0x8bf3, 0x00},
+ {0x8bf4, 0x00},
+ {0x8bf5, 0x00},
+ {0x8bf6, 0x00},
+ {0x8bf7, 0x00},
+ {0x8bf8, 0x00},
+ {0x8bf9, 0x00},
+ {0x8bfa, 0x00},
+ {0x8bfb, 0x00},
+ {0x8bfc, 0x00},
+ {0x8bfd, 0x00},
+ {0x8bfe, 0x00},
+ {0x8bff, 0x00},
+ {0x8c00, 0x00},
+ {0x8c01, 0x00},
+ {0x8c02, 0x00},
+ {0x8c03, 0x00},
+ {0x8c04, 0x00},
+ {0x8c05, 0x00},
+ {0x8c06, 0x00},
+ {0x8c07, 0x00},
+ {0x8c08, 0x00},
+ {0x8c09, 0x00},
+ {0x8c0a, 0x00},
+ {0x8c0b, 0x00},
+ {0x8c0c, 0x00},
+ {0x8c0d, 0x00},
+ {0x8c0e, 0x00},
+ {0x8c0f, 0x00},
+ {0x8c10, 0x00},
+ {0x8c11, 0x00},
+ {0x8c12, 0x00},
+ {0x8c13, 0x00},
+ {0x8c14, 0x00},
+ {0x8c15, 0x00},
+ {0x8c16, 0x00},
+ {0x8c17, 0x00},
+ {0x8c18, 0x00},
+ {0x8c19, 0x00},
+ {0x8c1a, 0x00},
+ {0x8c1b, 0x00},
+ {0x8c1c, 0x00},
+ {0x8c1d, 0x00},
+ {0x8c1e, 0x00},
+ {0x8c1f, 0x00},
+ {0x8c20, 0x00},
+ {0x8c21, 0x00},
+ {0x8c22, 0x00},
+ {0x8c23, 0x00},
+ {0x8c24, 0x00},
+ {0x8c25, 0x00},
+ {0x8c26, 0x00},
+ {0x8c27, 0x00},
+ {0x8c28, 0x00},
+ {0x8c29, 0x00},
+ {0x8c2a, 0x00},
+ {0x8c2b, 0x00},
+ {0x8c2c, 0x00},
+ {0x8c2d, 0x00},
+ {0x8c2e, 0x00},
+ {0x8c2f, 0x00},
+ {0x8c30, 0x00},
+ {0x8c31, 0x00},
+ {0x8c32, 0x00},
+ {0x8c33, 0x00},
+ {0x8c34, 0x00},
+ {0x8c35, 0x00},
+ {0x8c36, 0x00},
+ {0x8c37, 0x00},
+ {0x8c38, 0x00},
+ {0x8c39, 0x00},
+ {0x8c3a, 0x00},
+ {0x8c3b, 0x00},
+ {0x8c3c, 0x00},
+ {0x8c3d, 0x00},
+ {0x8c3e, 0x00},
+ {0x8c3f, 0x00},
+ {0x8c40, 0x00},
+ {0x8c41, 0x00},
+ {0x8c42, 0x00},
+ {0x8c43, 0x00},
+ {0x8c44, 0x00},
+ {0x8c45, 0x00},
+ {0x8c46, 0x00},
+ {0x8c47, 0x00},
+ {0x8c48, 0x00},
+ {0x8c49, 0x00},
+ {0x8c4a, 0x00},
+ {0x8c4b, 0x00},
+ {0x8c4c, 0x00},
+ {0x8c4d, 0x00},
+ {0x8c4e, 0x00},
+ {0x8c4f, 0x00},
+ {0x8c50, 0x00},
+ {0x8c51, 0x00},
+ {0x8c52, 0x00},
+ {0x8c53, 0x00},
+ {0x8c54, 0x00},
+ {0x8c55, 0x00},
+ {0x8c56, 0x00},
+ {0x8c57, 0x00},
+ {0x8c58, 0x00},
+ {0x8c59, 0x00},
+ {0x8c5a, 0x00},
+ {0x8c5b, 0x00},
+ {0x8c5c, 0x00},
+ {0x8c5d, 0x00},
+ {0x8c5e, 0x00},
+ {0x8c5f, 0x00},
+ {0x8c60, 0x00},
+ {0x8c61, 0x00},
+ {0x8c62, 0x00},
+ {0x8c63, 0x00},
+ {0x8c64, 0x00},
+ {0x8c65, 0x00},
+ {0x8c66, 0x00},
+ {0x8c67, 0x00},
+ {0x8c68, 0x00},
+ {0x8c69, 0x00},
+ {0x8c6a, 0x00},
+ {0x8c6b, 0x00},
+ {0x8c6c, 0x00},
+ {0x8c6d, 0x00},
+ {0x8c6e, 0x00},
+ {0x8c6f, 0x00},
+ {0x8c70, 0x00},
+ {0x8c71, 0x00},
+ {0x8c72, 0x00},
+ {0x8c73, 0x00},
+ {0x8c74, 0x00},
+ {0x8c75, 0x00},
+ {0x8c76, 0x00},
+ {0x8c77, 0x00},
+ {0x8c78, 0x00},
+ {0x8c79, 0x00},
+ {0x8c7a, 0x00},
+ {0x8c7b, 0x00},
+ {0x8c7c, 0x00},
+ {0x8c7d, 0x00},
+ {0x8c7e, 0x00},
+ {0x8c7f, 0x00},
+ {0x8c80, 0x00},
+ {0x8c81, 0x00},
+ {0x8c82, 0x00},
+ {0x8c83, 0x00},
+ {0x8c84, 0x00},
+ {0x8c85, 0x00},
+ {0x8c86, 0x00},
+ {0x8c87, 0x00},
+ {0x8c88, 0x00},
+ {0x8c89, 0x00},
+ {0x8c8a, 0x00},
+ {0x8c8b, 0x00},
+ {0x8c8c, 0x00},
+ {0x8c8d, 0x00},
+ {0x8c8e, 0x00},
+ {0x8c8f, 0x00},
+ {0x8c90, 0x00},
+ {0x8c91, 0x00},
+ {0x8c92, 0x00},
+ {0x8c93, 0x00},
+ {0x8c94, 0x00},
+ {0x8c95, 0x00},
+ {0x8c96, 0x00},
+ {0x8c97, 0x00},
+ {0x8c98, 0x00},
+ {0x8c99, 0x00},
+ {0x8c9a, 0x00},
+ {0x8c9b, 0x00},
+ {0x8c9c, 0x00},
+ {0x8c9d, 0x00},
+ {0x8c9e, 0x00},
+ {0x8c9f, 0x00},
+ {0x8ca0, 0x00},
+ {0x8ca1, 0x00},
+ {0x8ca2, 0x00},
+ {0x8ca3, 0x00},
+ {0x8ca4, 0x00},
+ {0x8ca5, 0x00},
+ {0x8ca6, 0x00},
+ {0x8ca7, 0x00},
+ {0x8ca8, 0x00},
+ {0x8ca9, 0x00},
+ {0x8caa, 0x00},
+ {0x8cab, 0x00},
+ {0x8cac, 0x00},
+ {0x8cad, 0x00},
+ {0x8cae, 0x00},
+ {0x8caf, 0x00},
+ {0x8cb0, 0x00},
+ {0x8cb1, 0x00},
+ {0x8cb2, 0x00},
+ {0x8cb3, 0x00},
+ {0x8cb4, 0x00},
+ {0x8cb5, 0x00},
+ {0x8cb6, 0x00},
+ {0x8cb7, 0x00},
+ {0x8cb8, 0x00},
+ {0x8cb9, 0x00},
+ {0x8cba, 0x00},
+ {0x8cbb, 0x00},
+ {0x8cbc, 0x00},
+ {0x8cbd, 0x00},
+ {0x8cbe, 0x00},
+ {0x8cbf, 0x00},
+ {0x8cc0, 0x00},
+ {0x8cc1, 0x00},
+ {0x8cc2, 0x00},
+ {0x8cc3, 0x00},
+ {0x8cc4, 0x00},
+ {0x8cc5, 0x00},
+ {0x8cc6, 0x00},
+ {0x8cc7, 0x00},
+ {0x8cc8, 0x00},
+ {0x8cc9, 0x00},
+ {0x8cca, 0x00},
+ {0x8ccb, 0x00},
+ {0x8ccc, 0x00},
+ {0x8ccd, 0x00},
+ {0x8cce, 0x00},
+ {0x8ccf, 0x00},
+ {0x8cd0, 0x00},
+ {0x8cd1, 0x00},
+ {0x8cd2, 0x00},
+ {0x8cd3, 0x00},
+ {0x8cd4, 0x00},
+ {0x8cd5, 0x00},
+ {0x8cd6, 0x00},
+ {0x8cd7, 0x00},
+ {0x8cd8, 0x00},
+ {0x8cd9, 0x00},
+ {0x8cda, 0x00},
+ {0x8cdb, 0x00},
+ {0x8cdc, 0x00},
+ {0x8cdd, 0x00},
+ {0x8cde, 0x00},
+ {0x8cdf, 0x00},
+ {0x8ce0, 0x00},
+ {0x8ce1, 0x00},
+ {0x8ce2, 0x00},
+ {0x8ce3, 0x00},
+ {0x8ce4, 0x00},
+ {0x8ce5, 0x00},
+ {0x8ce6, 0x00},
+ {0x8ce7, 0x00},
+ {0x8ce8, 0x00},
+ {0x8ce9, 0x00},
+ {0x8cea, 0x00},
+ {0x8ceb, 0x00},
+ {0x8cec, 0x00},
+ {0x8ced, 0x00},
+ {0x8cee, 0x00},
+ {0x8cef, 0x00},
+ {0x8cf0, 0x00},
+ {0x8cf1, 0x00},
+ {0x8cf2, 0x00},
+ {0x8cf3, 0x00},
+ {0x8cf4, 0x00},
+ {0x8cf5, 0x00},
+ {0x8cf6, 0x00},
+ {0x8cf7, 0x00},
+ {0x8cf8, 0x00},
+ {0x8cf9, 0x00},
+ {0x8cfa, 0x00},
+ {0x8cfb, 0x00},
+ {0x8cfc, 0x00},
+ {0x8cfd, 0x00},
+ {0x8cfe, 0x00},
+ {0x8cff, 0x00},
+ {0x8d00, 0x00},
+ {0x8d01, 0x00},
+ {0x8d02, 0x00},
+ {0x8d03, 0x00},
+ {0x8d04, 0x00},
+ {0x8d05, 0x00},
+ {0x8d06, 0x00},
+ {0x8d07, 0x00},
+ {0x8d08, 0x00},
+ {0x8d09, 0x00},
+ {0x8d0a, 0x00},
+ {0x8d0b, 0x00},
+ {0x8d0c, 0x00},
+ {0x8d0d, 0x00},
+ {0x8d0e, 0x00},
+ {0x8d0f, 0x00},
+ {0x8d10, 0x00},
+ {0x8d11, 0x00},
+ {0x8d12, 0x00},
+ {0x8d13, 0x00},
+ {0x8d14, 0x00},
+ {0x8d15, 0x00},
+ {0x8d16, 0x00},
+ {0x8d17, 0x00},
+ {0x8d18, 0x00},
+ {0x8d19, 0x00},
+ {0x8d1a, 0x00},
+ {0x8d1b, 0x00},
+ {0x8d1c, 0x00},
+ {0x8d1d, 0x00},
+ {0x8d1e, 0x00},
+ {0x8d1f, 0x00},
+ {0x8d20, 0x00},
+ {0x8d21, 0x00},
+ {0x8d22, 0x00},
+ {0x8d23, 0x00},
+ {0x8d24, 0x00},
+ {0x8d25, 0x00},
+ {0x8d26, 0x00},
+ {0x8d27, 0x00},
+ {0x8d28, 0x00},
+ {0x8d29, 0x00},
+ {0x8d2a, 0x00},
+ {0x8d2b, 0x00},
+ {0x8d2c, 0x00},
+ {0x8d2d, 0x00},
+ {0x8d2e, 0x00},
+ {0x8d2f, 0x00},
+ {0x8d30, 0x00},
+ {0x8d31, 0x00},
+ {0x8d32, 0x00},
+ {0x8d33, 0x00},
+ {0x8d34, 0x00},
+ {0x8d35, 0x00},
+ {0x8d36, 0x00},
+ {0x8d37, 0x00},
+ {0x8d38, 0x00},
+ {0x8d39, 0x00},
+ {0x8d3a, 0x00},
+ {0x8d3b, 0x00},
+ {0x8d3c, 0x00},
+ {0x8d3d, 0x00},
+ {0x8d3e, 0x00},
+ {0x8d3f, 0x00},
+ {0x8d40, 0x00},
+ {0x8d41, 0x00},
+ {0x8d42, 0x00},
+ {0x8d43, 0x00},
+ {0x8d44, 0x00},
+ {0x8d45, 0x00},
+ {0x8d46, 0x00},
+ {0x8d47, 0x00},
+ {0x8d48, 0x00},
+ {0x8d49, 0x00},
+ {0x8d4a, 0x00},
+ {0x8d4b, 0x00},
+ {0x8d4c, 0x00},
+ {0x8d4d, 0x00},
+ {0x8d4e, 0x00},
+ {0x8d4f, 0x00},
+ {0x8d50, 0x00},
+ {0x8d51, 0x00},
+ {0x8d52, 0x00},
+ {0x8d53, 0x00},
+ {0x8d54, 0x00},
+ {0x8d55, 0x00},
+ {0x8d56, 0x00},
+ {0x8d57, 0x00},
+ {0x8d58, 0x00},
+ {0x8d59, 0x00},
+ {0x8d5a, 0x00},
+ {0x8d5b, 0x00},
+ {0x8d5c, 0x00},
+ {0x8d5d, 0x00},
+ {0x8d5e, 0x00},
+ {0x8d5f, 0x00},
+ {0x8d60, 0x00},
+ {0x8d61, 0x00},
+ {0x8d62, 0x00},
+ {0x8d63, 0x00},
+ {0x8d64, 0x00},
+ {0x8d65, 0x00},
+ {0x8d66, 0x00},
+ {0x8d67, 0x00},
+ {0x8d68, 0x00},
+ {0x8d69, 0x00},
+ {0x8d6a, 0x00},
+ {0x8d6b, 0x00},
+ {0x8d6c, 0x00},
+ {0x8d6d, 0x00},
+ {0x8d6e, 0x00},
+ {0x8d6f, 0x00},
+ {0x8d70, 0x00},
+ {0x8d71, 0x00},
+ {0x8d72, 0x00},
+ {0x8d73, 0x00},
+ {0x8d74, 0x00},
+ {0x8d75, 0x00},
+ {0x8d76, 0x00},
+ {0x8d77, 0x00},
+ {0x8d78, 0x00},
+ {0x8d79, 0x00},
+ {0x8d7a, 0x00},
+ {0x8d7b, 0x00},
+ {0x8d7c, 0x00},
+ {0x8d7d, 0x00},
+ {0x8d7e, 0x00},
+ {0x8d7f, 0x00},
+ {0x8d80, 0x00},
+ {0x8d81, 0x00},
+ {0x8d82, 0x00},
+ {0x8d83, 0x00},
+ {0x8d84, 0x00},
+ {0x8d85, 0x00},
+ {0x8d86, 0x00},
+ {0x8d87, 0x00},
+ {0x8d88, 0x00},
+ {0x8d89, 0x00},
+ {0x8d8a, 0x00},
+ {0x8d8b, 0x00},
+ {0x8d8c, 0x00},
+ {0x8d8d, 0x00},
+ {0x8d8e, 0x00},
+ {0x8d8f, 0x00},
+ {0x8d90, 0x00},
+ {0x8d91, 0x00},
+ {0x8d92, 0x00},
+ {0x8d93, 0x00},
+ {0x8d94, 0x00},
+ {0x8d95, 0x00},
+ {0x8d96, 0x00},
+ {0x8d97, 0x00},
+ {0x8d98, 0x00},
+ {0x8d99, 0x00},
+ {0x8d9a, 0x00},
+ {0x8d9b, 0x00},
+ {0x8d9c, 0x00},
+ {0x8d9d, 0x00},
+ {0x8d9e, 0x00},
+ {0x8d9f, 0x00},
+ {0x8da0, 0x00},
+ {0x8da1, 0x00},
+ {0x8da2, 0x00},
+ {0x8da3, 0x00},
+ {0x8da4, 0x00},
+ {0x8da5, 0x00},
+ {0x8da6, 0x00},
+ {0x8da7, 0x00},
+ {0x8da8, 0x00},
+ {0x8da9, 0x00},
+ {0x8daa, 0x00},
+ {0x8dab, 0x00},
+ {0x8dac, 0x00},
+ {0x8dad, 0x00},
+ {0x8dae, 0x00},
+ {0x8daf, 0x00},
+ {0x8db0, 0x00},
+ {0x8db1, 0x00},
+ {0x8db2, 0x00},
+ {0x8db3, 0x00},
+ {0x8db4, 0x00},
+ {0x8db5, 0x00},
+ {0x8db6, 0x00},
+ {0x8db7, 0x00},
+ {0x8db8, 0x00},
+ {0x8db9, 0x00},
+ {0x8dba, 0x00},
+ {0x8dbb, 0x00},
+ {0x8dbc, 0x00},
+ {0x8dbd, 0x00},
+ {0x8dbe, 0x00},
+ {0x8dbf, 0x00},
+ {0x8dc0, 0x00},
+ {0x8dc1, 0x00},
+ {0x8dc2, 0x00},
+ {0x8dc3, 0x00},
+ {0x8dc4, 0x00},
+ {0x8dc5, 0x00},
+ {0x8dc6, 0x00},
+ {0x8dc7, 0x00},
+ {0x8dc8, 0x00},
+ {0x8dc9, 0x00},
+ {0x8dca, 0x00},
+ {0x8dcb, 0x00},
+ {0x8dcc, 0x00},
+ {0x8dcd, 0x00},
+ {0x8dce, 0x00},
+ {0x8dcf, 0x00},
+ {0x8dd0, 0x00},
+ {0x8dd1, 0x00},
+ {0x8dd2, 0x00},
+ {0x8dd3, 0x00},
+ {0x8dd4, 0x00},
+ {0x8dd5, 0x00},
+ {0x8dd6, 0x00},
+ {0x8dd7, 0x00},
+ {0x8dd8, 0x00},
+ {0x8dd9, 0x00},
+ {0x8dda, 0x00},
+ {0x8ddb, 0x00},
+ {0x8ddc, 0x00},
+ {0x8ddd, 0x00},
+ {0x8dde, 0x00},
+ {0x8ddf, 0x00},
+ {0x8de0, 0x00},
+ {0x8de1, 0x00},
+ {0x8de2, 0x00},
+ {0x8de3, 0x00},
+ {0x8de4, 0x00},
+ {0x8de5, 0x00},
+ {0x8de6, 0x00},
+ {0x8de7, 0x00},
+ {0x8de8, 0x00},
+ {0x8de9, 0x00},
+ {0x8dea, 0x00},
+ {0x8deb, 0x00},
+ {0x8dec, 0x00},
+ {0x8ded, 0x00},
+ {0x8dee, 0x00},
+ {0x8def, 0x00},
+ {0x8df0, 0x00},
+ {0x8df1, 0x00},
+ {0x8df2, 0x00},
+ {0x8df3, 0x00},
+ {0x8df4, 0x00},
+ {0x8df5, 0x00},
+ {0x8df6, 0x00},
+ {0x8df7, 0x00},
+ {0x8df8, 0x00},
+ {0x8df9, 0x00},
+ {0x8dfa, 0x00},
+ {0x8dfb, 0x00},
+ {0x8dfc, 0x00},
+ {0x8dfd, 0x00},
+ {0x8dfe, 0x00},
+ {0x8dff, 0x00},
+ {0x8e00, 0x11},
+ {0x8e01, 0x02},
+ {0x8e02, 0x28},
+ {0x8e03, 0x09},
+ {0x8e04, 0x00},
+ {0x8e05, 0x12},
+ {0x8e06, 0x4f},
+ {0x8e07, 0x56},
+ {0x8e08, 0x54},
+ {0x8e09, 0x20},
+ {0x8e0a, 0x20},
+ {0x8e0b, 0x20},
+ {0x8e0c, 0x20},
+ {0x8e0d, 0x20},
+ {0x8e0e, 0x20},
+ {0x8e0f, 0x01},
+ {0x8e10, 0x10},
+ {0x8e11, 0x00},
+ {0x8e12, 0x56},
+ {0x8e13, 0x40},
+ {0x8e14, 0x1a},
+ {0x8e15, 0x30},
+ {0x8e16, 0x29},
+ {0x8e17, 0x7e},
+ {0x8e18, 0x00},
+ {0x8e19, 0x30},
+ {0x8e1a, 0x04},
+ {0x8e1b, 0x20},
+ {0x8e1c, 0xdf},
+ {0x8e1d, 0x30},
+ {0x8e1e, 0x05},
+ {0x8e1f, 0x40},
+ {0x8e20, 0xbf},
+ {0x8e21, 0x50},
+ {0x8e22, 0x25},
+ {0x8e23, 0x04},
+ {0x8e24, 0xfb},
+ {0x8e25, 0x50},
+ {0x8e26, 0x03},
+ {0x8e27, 0x00},
+ {0x8e28, 0xfd},
+ {0x8e29, 0x50},
+ {0x8e2a, 0x27},
+ {0x8e2b, 0x01},
+ {0x8e2c, 0xfe},
+ {0x8e2d, 0x60},
+ {0x8e2e, 0x00},
+ {0x8e2f, 0x11},
+ {0x8e30, 0x00},
+ {0x8e31, 0x3f},
+ {0x8e32, 0x05},
+ {0x8e33, 0x30},
+ {0x8e34, 0x00},
+ {0x8e35, 0x3f},
+ {0x8e36, 0x06},
+ {0x8e37, 0x22},
+ {0x8e38, 0x00},
+ {0x8e39, 0x3f},
+ {0x8e3a, 0x01},
+ {0x8e3b, 0x29},
+ {0x8e3c, 0x00},
+ {0x8e3d, 0x3f},
+ {0x8e3e, 0x02},
+ {0x8e3f, 0x00},
+ {0x8e40, 0x00},
+ {0x8e41, 0x36},
+ {0x8e42, 0x06},
+ {0x8e43, 0x07},
+ {0x8e44, 0x00},
+ {0x8e45, 0x3f},
+ {0x8e46, 0x0b},
+ {0x8e47, 0x0f},
+ {0x8e48, 0xf0},
+ {0x8e49, 0x30},
+ {0x8e4a, 0x01},
+ {0x8e4b, 0x40},
+ {0x8e4c, 0xbf},
+ {0x8e4d, 0x30},
+ {0x8e4e, 0x01},
+ {0x8e4f, 0x00},
+ {0x8e50, 0xbf},
+ {0x8e51, 0x30},
+ {0x8e52, 0x29},
+ {0x8e53, 0x70},
+ {0x8e54, 0x00},
+ {0x8e55, 0x3a},
+ {0x8e56, 0x00},
+ {0x8e57, 0x01},
+ {0x8e58, 0xfe},
+ {0x8e59, 0x3a},
+ {0x8e5a, 0x00},
+ {0x8e5b, 0x00},
+ {0x8e5c, 0xfe},
+ {0x8e5d, 0x36},
+ {0x8e5e, 0x03},
+ {0x8e5f, 0x36},
+ {0x8e60, 0x02},
+ {0x8e61, 0x41},
+ {0x8e62, 0x44},
+ {0x8e63, 0x58},
+ {0x8e64, 0x20},
+ {0x8e65, 0x18},
+ {0x8e66, 0x10},
+ {0x8e67, 0x0a},
+ {0x8e68, 0x04},
+ {0x8e69, 0x04},
+ {0x8e6a, 0x00},
+ {0x8e6b, 0x03},
+ {0x8e6c, 0xff},
+ {0x8e6d, 0x64},
+ {0x8e6e, 0x00},
+ {0x8e6f, 0x00},
+ {0x8e70, 0x80},
+ {0x8e71, 0x00},
+ {0x8e72, 0x00},
+ {0x8e73, 0x00},
+ {0x8e74, 0x00},
+ {0x8e75, 0x00},
+ {0x8e76, 0x00},
+ {0x8e77, 0x02},
+ {0x8e78, 0x04},
+ {0x8e79, 0x06},
+ {0x8e7a, 0x00},
+ {0x8e7b, 0x03},
+ {0x8e7c, 0x98},
+ {0x8e7d, 0x00},
+ {0x8e7e, 0xcc},
+ {0x8e7f, 0x50},
+ {0x8e80, 0x3c},
+ {0x8e81, 0x28},
+ {0x8e82, 0x1e},
+ {0x8e83, 0x0c},
+ {0x8e84, 0x0c},
+ {0x8e85, 0x00},
+ {0x8e86, 0x00},
+ {0x8e87, 0x00},
+ {0x8e88, 0x6e},
+ {0x8e89, 0x05},
+ {0x8e8a, 0x05},
+ {0x8e8b, 0x00},
+ {0x8e8c, 0xa5},
+ {0x8e8d, 0x5a},
+ {0x3022, 0x00},
+ {0x3023, 0x00},
+ {0x3024, 0x00},
+ {0x3025, 0x00},
+ {0x3026, 0x00},
+ {0x3027, 0x00},
+ {0x3028, 0x00},
+ {0x3029, 0xFF},
+ {0x3000, 0x00},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg tbl_single_focus[] = {
+ {0x3023, 0x01},
+ {0x3022, 0x03},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg tbl_release_focus[] = {
+ {0x3023, 0x01},
+ {0x3022, 0x08},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+#endif
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c
index 3adb46a..3e2d23a 100644
--- a/drivers/media/video/tegra/ov5650.c
+++ b/drivers/media/video/tegra/ov5650.c
@@ -39,6 +39,11 @@ struct ov5650_info {
enum StereoCameraMode camera_mode;
struct ov5650_sensor left;
struct ov5650_sensor right;
+ struct ov5650_sensordata sensor_data;
+ struct mutex mutex_le;
+ struct mutex mutex_ri;
+ int power_refcnt_le;
+ int power_refcnt_ri;
u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
@@ -788,7 +793,7 @@ static int ov5650_read_reg(struct i2c_client *client, u16 addr, u8 *val)
err = i2c_transfer(client->adapter, msg, 2);
- if (err != 1)
+ if (err != 2)
return -EINVAL;
*val = data[2];
@@ -1245,31 +1250,71 @@ static int ov5650_test_pattern(struct ov5650_info *info,
}
static int set_power_helper(struct ov5650_platform_data *pdata,
- int powerLevel)
+ int powerLevel, int *ref_cnt)
{
if (pdata) {
- if (powerLevel && pdata->power_on)
- pdata->power_on();
- else if (pdata->power_off)
- pdata->power_off();
+ if (powerLevel && pdata->power_on) {
+ if (*ref_cnt == 0)
+ pdata->power_on();
+ *ref_cnt = *ref_cnt + 1;
+ }
+ else if (pdata->power_off) {
+ *ref_cnt = *ref_cnt - 1;
+ if (*ref_cnt <= 0)
+ pdata->power_off();
+ }
}
return 0;
}
-static int ov5650_set_power(int powerLevel)
+static int ov5650_set_power(struct ov5650_info *info, int powerLevel)
{
pr_info("%s: powerLevel=%d camera mode=%d\n", __func__, powerLevel,
- stereo_ov5650_info->camera_mode);
+ info->camera_mode);
- if (StereoCameraMode_Left & stereo_ov5650_info->camera_mode)
- set_power_helper(stereo_ov5650_info->left.pdata, powerLevel);
+ if (StereoCameraMode_Left & info->camera_mode) {
+ mutex_lock(&info->mutex_le);
+ set_power_helper(info->left.pdata, powerLevel,
+ &info->power_refcnt_le);
+ mutex_unlock(&info->mutex_le);
+ }
- if (StereoCameraMode_Right & stereo_ov5650_info->camera_mode)
- set_power_helper(stereo_ov5650_info->right.pdata, powerLevel);
+ if (StereoCameraMode_Right & info->camera_mode) {
+ mutex_lock(&info->mutex_ri);
+ set_power_helper(info->right.pdata, powerLevel,
+ &info->power_refcnt_ri);
+ mutex_unlock(&info->mutex_ri);
+ }
return 0;
}
+static int ov5650_get_sensor_id(struct ov5650_info *info)
+{
+ int ret = 0;
+ int i;
+ u8 bak;
+
+ pr_info("%s\n", __func__);
+ if (info->sensor_data.fuse_id_size)
+ return 0;
+
+ ov5650_set_power(info, 1);
+
+ for (i = 0; i < 5; i++) {
+ ret |= ov5650_write_reg_helper(info, 0x3d00, i);
+ ret |= ov5650_read_reg_helper(info, 0x3d04,
+ &bak);
+ info->sensor_data.fuse_id[i] = bak;
+ }
+
+ if (!ret)
+ info->sensor_data.fuse_id_size = i;
+
+ ov5650_set_power(info, 0);
+ return ret;
+}
+
static long ov5650_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1280,13 +1325,13 @@ static long ov5650_ioctl(struct file *file,
case OV5650_IOCTL_SET_CAMERA_MODE:
{
if (info->camera_mode != arg) {
- err = ov5650_set_power(0);
+ err = ov5650_set_power(info, 0);
if (err) {
pr_info("%s %d\n", __func__, __LINE__);
return err;
}
info->camera_mode = arg;
- err = ov5650_set_power(1);
+ err = ov5650_set_power(info, 1);
if (err)
return err;
}
@@ -1344,6 +1389,21 @@ static long ov5650_ioctl(struct file *file,
}
return ov5650_set_group_hold(info, &ae);
}
+ case OV5650_IOCTL_GET_SENSORDATA:
+ {
+ err = ov5650_get_sensor_id(info);
+ if (err) {
+ pr_err("%s %d %d\n", __func__, __LINE__, err);
+ return err;
+ }
+ if (copy_to_user((void __user *)arg,
+ &info->sensor_data,
+ sizeof(struct ov5650_sensordata))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ }
default:
return -EINVAL;
}
@@ -1354,13 +1414,15 @@ static int ov5650_open(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
file->private_data = stereo_ov5650_info;
- ov5650_set_power(1);
+ ov5650_set_power(stereo_ov5650_info, 1);
return 0;
}
int ov5650_release(struct inode *inode, struct file *file)
{
- ov5650_set_power(0);
+ struct ov5650_info *info = file->private_data;
+
+ ov5650_set_power(info, 0);
file->private_data = NULL;
return 0;
}
@@ -1426,6 +1488,8 @@ static int left_ov5650_probe(struct i2c_client *client,
stereo_ov5650_info->left.pdata = client->dev.platform_data;
stereo_ov5650_info->left.i2c_client = client;
+ mutex_init(&stereo_ov5650_info->mutex_le);
+ mutex_init(&stereo_ov5650_info->mutex_ri);
return 0;
}
@@ -1517,4 +1581,4 @@ static void __exit ov5650_exit(void)
module_init(ov5650_init);
module_exit(ov5650_exit);
-
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/ov9726.c b/drivers/media/video/tegra/ov9726.c
index 655d07c..378d46f 100644
--- a/drivers/media/video/tegra/ov9726.c
+++ b/drivers/media/video/tegra/ov9726.c
@@ -843,3 +843,4 @@ static void __exit ov9726_exit(void)
module_init(ov9726_init);
module_exit(ov9726_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/sh532u.c b/drivers/media/video/tegra/sh532u.c
index 7db14fcf2..f41b44ce 100644
--- a/drivers/media/video/tegra/sh532u.c
+++ b/drivers/media/video/tegra/sh532u.c
@@ -1,7 +1,7 @@
/*
* SH532U focuser driver.
*
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-2012 NVIDIA Corporation.
*
* 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
@@ -21,7 +21,7 @@
/* Implementation
* --------------
* The board level details about the device need to be provided in the board
- * file with the sh532u_platform_data structure.
+ * file with the <device>_platform_data structure.
* Standard among NVC kernel drivers in this structure is:
* .cfg = Use the NVC_CFG_ defines that are in nvc.h.
* Descriptions of the configuration options are with the defines.
@@ -40,11 +40,26 @@
* .num = 2,
* .sync = 1,
* The above example sync's device 1 and 2.
+ * To disable sync, set .sync = 0. Note that the .num = 0 device is
+ * not allowed to be synced to.
* This is typically used for stereo applications.
* .dev_name = The MISC driver name the device registers as. If not used,
* then the part number of the device is used for the driver name.
* If using the NVC user driver then use the name found in this
* driver under _default_pdata.
+ * .gpio_count = The ARRAY_SIZE of the nvc_gpio_pdata table.
+ * .gpio = A pointer to the nvc_gpio_pdata structure's platform GPIO data.
+ * The GPIO mechanism works by cross referencing the .gpio_type key
+ * among the nvc_gpio_pdata GPIO data and the driver's nvc_gpio_init
+ * GPIO data to build a GPIO table the driver can use. The GPIO's
+ * defined in the device header file's _gpio_type enum are the
+ * gpio_type keys for the nvc_gpio_pdata and nvc_gpio_init structures.
+ * These need to be present in the board file's nvc_gpio_pdata
+ * structure for the GPIO's that are used.
+ * The driver's GPIO logic uses assert/deassert throughout until the
+ * low level _gpio_wr/rd calls where the .assert_high is used to
+ * convert the value to the correct signal level.
+ * See the GPIO notes in nvc.h for additional information.
*
* The following is specific to NVC kernel focus drivers:
* .nvc = Pointer to the nvc_focus_nvc structure. This structure needs to
@@ -52,27 +67,21 @@
* .cap = Pointer to the nvc_focus_cap structure. This structure needs to
* be defined and populated if overriding the driver defaults.
*
- * The following is specific to only this NVC kernel focus driver:
+ * The following is specific to this NVC kernel focus driver:
* .info = Pointer to the sh532u_pdata_info structure. This structure does
* not need to be defined and populated unless overriding ROM data.
.* .i2c_addr_rom = The I2C address of the onboard ROM.
- * .gpio_reset = The GPIO connected to the devices reset. If not used then
- * leave blank.
- * .gpio_en = Due to a Linux limitation, a GPIO is defined to "enable" the
- * device. This workaround is for when the device's power GPIO's
- * are behind an I2C expander. The Linux limitation doesn't allow
- * the I2C GPIO expander to be ready for use when this device is
- * probed. When this problem is solved, this driver needs to
- * remove the gpio_en WAR.
*
- * Power Requirements
- * The board power file must contain the following labels for the power
- * regulator(s) of this device:
- * "vdd" = the power regulator for the device's power.
- * "vdd_i2c" = the power regulator for the I2C power.
- *
- * The above values should be all that is needed to use the device with this
- * driver. Modifications of this driver should not be needed.
+ * Power Requirements:
+ * The device's header file defines the voltage regulators needed with the
+ * enumeration <device>_vreg. The order these are enumerated is the order
+ * the regulators will be enabled when powering on the device. When the
+ * device is powered off the regulators are disabled in descending order.
+ * The <device>_vregs table in this driver uses the nvc_regulator_init
+ * structure to define the regulator ID strings that go with the regulators
+ * defined with <device>_vreg. These regulator ID strings (or supply names)
+ * will be used in the regulator_get function in the _vreg_init function.
+ * The board power file and <device>_vregs regulator ID strings must match.
*/
@@ -85,10 +94,10 @@
#include <linux/list.h>
#include <linux/jiffies.h>
#include <linux/gpio.h>
-#include <media/nvc.h>
#include <media/sh532u.h>
-#define SH532U_ID 0xF0
+#define SH532U_ID 0x0532
+#define SH532U_STARTUP_DELAY_MS 10
/* defaults if no ROM data */
#define SH532U_HYPERFOCAL_RATIO 1836 /* 41.2f/224.4f Ratio source: SEMCO */
/* _HYPERFOCAL_RATIO is multiplied and _HYPERFOCAL_DIV divides for float */
@@ -96,10 +105,6 @@
#define SH532U_FOCAL_LENGTH 0x408D70A4
#define SH532U_FNUMBER 0x40333333
#define SH532U_MAX_APERATURE 0x3FCA0EA1
-/* SH532U_CAPS_VER = 0: invalid value */
-/* SH532U_CAPS_VER = 1: added NVC_PARAM_STS */
-/* SH532U_CAPS_VER = 2: expanded nvc_focus_cap */
-#define SH532U_CAPS_VER 2
#define SH532U_ACTUATOR_RANGE 1000
#define SH532U_SETTLETIME 30
#define SH532U_FOCUS_MACRO 950
@@ -110,24 +115,42 @@
#define SH532U_POS_HIGH_DEFAULT 0x6000
+static u8 sh532u_ids[] = {
+ 0xF0,
+};
+
+static struct nvc_gpio_init sh532u_gpios[] = {
+ { SH532U_GPIO_RESET, GPIOF_OUT_INIT_LOW, "reset", false, true, },
+ { SH532U_GPIO_I2CMUX, 0, "i2c_mux", 0, false, },
+ { SH532U_GPIO_GP1, 0, "gp1", 0, false, },
+ { SH532U_GPIO_GP2, 0, "gp2", 0, false, },
+ { SH532U_GPIO_GP3, 0, "gp3", 0, false, },
+};
+
+static struct nvc_regulator_init sh532u_vregs[] = {
+ { SH532U_VREG_AVDD, "avdd", },
+ { SH532U_VREG_DVDD, "dvdd", },
+};
+
struct sh532u_info {
atomic_t in_use;
struct i2c_client *i2c_client;
struct sh532u_platform_data *pdata;
struct miscdevice miscdev;
struct list_head list;
+ struct nvc_gpio gpio[ARRAY_SIZE(sh532u_gpios)];
+ struct nvc_regulator vreg[ARRAY_SIZE(sh532u_vregs)];
int pwr_api;
int pwr_dev;
- struct nvc_regulator vreg_vdd;
- struct nvc_regulator vreg_i2c;
u8 s_mode;
struct sh532u_info *s_info;
+ u8 id_minor;
unsigned i2c_addr_rom;
struct nvc_focus_nvc nvc;
struct nvc_focus_cap cap;
enum nvc_focus_sts sts;
struct sh532u_pdata_info cfg;
- bool gpio_flag_reset;
+ bool reset_flag;
bool init_cal_flag;
s16 abs_base;
u32 abs_range;
@@ -143,7 +166,7 @@ static struct sh532u_pdata_info sh532u_default_info = {
};
static struct nvc_focus_cap sh532u_default_cap = {
- .version = SH532U_CAPS_VER,
+ .version = NVC_FOCUS_CAP_VER2,
.actuator_range = SH532U_ACTUATOR_RANGE,
.settle_time = SH532U_SETTLETIME,
.focus_macro = SH532U_FOCUS_MACRO,
@@ -299,91 +322,227 @@ static int sh532u_i2c_rd32(struct sh532u_info *info, u8 addr, u8 reg, u32 *val)
return 0;
}
-static void sh532u_gpio_en(struct sh532u_info *info, int val)
+static int sh532u_gpio_wr(struct sh532u_info *info,
+ enum sh532u_gpio i,
+ int val) /* val: 0=deassert, 1=assert */
{
- if (info->pdata->gpio_en)
- gpio_set_value_cansleep(info->pdata->gpio_en, val);
+ int err = -EINVAL;
+
+ if (info->gpio[i].flag) {
+ if (val)
+ val = 1;
+ if (!info->gpio[i].active_high)
+ val = !val;
+ val &= 1;
+ err = val;
+ gpio_set_value_cansleep(info->gpio[i].gpio, val);
+ dev_dbg(&info->i2c_client->dev, "%s %u %d\n",
+ __func__, info->gpio[i].gpio, val);
+ }
+ return err; /* return value written or error */
}
-static void sh532u_gpio_reset(struct sh532u_info *info, int val)
+static int sh532u_gpio_reset(struct sh532u_info *info, int val)
{
+ int err = 0;
+
if (val) {
- if (!info->gpio_flag_reset && info->pdata->gpio_reset) {
- gpio_set_value_cansleep(info->pdata->gpio_reset, 0);
+ if (!info->reset_flag) {
+ info->reset_flag = true;
+ err = sh532u_gpio_wr(info, SH532U_GPIO_RESET, 1);
+ if (err < 0)
+ return 0; /* flag no reset */
+
mdelay(1);
- gpio_set_value_cansleep(info->pdata->gpio_reset, 1);
- mdelay(10); /* delay for device startup */
- info->gpio_flag_reset = 1;
+ sh532u_gpio_wr(info, SH532U_GPIO_RESET, 0);
+ mdelay(SH532U_STARTUP_DELAY_MS); /* startup delay */
+ err = 1; /* flag that a reset was done */
}
} else {
- info->gpio_flag_reset = 0;
+ info->reset_flag = false;
}
+ return err;
}
-static void sh532u_pm_regulator_put(struct nvc_regulator *sreg)
+static void sh532u_gpio_able(struct sh532u_info *info, int val)
{
- regulator_put(sreg->vreg);
- sreg->vreg = NULL;
+ if (val) {
+ sh532u_gpio_wr(info, SH532U_GPIO_GP1, val);
+ sh532u_gpio_wr(info, SH532U_GPIO_GP2, val);
+ sh532u_gpio_wr(info, SH532U_GPIO_GP3, val);
+ } else {
+ sh532u_gpio_wr(info, SH532U_GPIO_GP3, val);
+ sh532u_gpio_wr(info, SH532U_GPIO_GP2, val);
+ sh532u_gpio_wr(info, SH532U_GPIO_GP1, val);
+ }
}
-static int sh532u_pm_regulator_get(struct sh532u_info *info,
- struct nvc_regulator *sreg,
- char vreg_name[])
+static void sh532u_gpio_exit(struct sh532u_info *info)
+{
+ unsigned i;
+
+ for (i = 0; i <= ARRAY_SIZE(sh532u_gpios); i++) {
+ if (info->gpio[i].flag && info->gpio[i].own) {
+ gpio_free(info->gpio[i].gpio);
+ info->gpio[i].own = false;
+ }
+ }
+}
+
+static void sh532u_gpio_init(struct sh532u_info *info)
+{
+ char label[32];
+ unsigned long flags;
+ unsigned type;
+ unsigned i;
+ unsigned j;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(sh532u_gpios); i++)
+ info->gpio[i].flag = false;
+ if (!info->pdata->gpio_count || !info->pdata->gpio)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(sh532u_gpios); i++) {
+ type = sh532u_gpios[i].gpio_type;
+ for (j = 0; j < info->pdata->gpio_count; j++) {
+ if (type == info->pdata->gpio[j].gpio_type)
+ break;
+ }
+ if (j == info->pdata->gpio_count)
+ continue;
+
+ info->gpio[type].gpio = info->pdata->gpio[j].gpio;
+ info->gpio[type].flag = true;
+ if (sh532u_gpios[i].use_flags) {
+ flags = sh532u_gpios[i].flags;
+ info->gpio[type].active_high =
+ sh532u_gpios[i].active_high;
+ } else {
+ info->gpio[type].active_high =
+ info->pdata->gpio[j].active_high;
+ if (info->gpio[type].active_high)
+ flags = GPIOF_OUT_INIT_LOW;
+ else
+ flags = GPIOF_OUT_INIT_HIGH;
+ }
+ if (!info->pdata->gpio[j].init_en)
+ continue;
+
+ snprintf(label, sizeof(label), "sh532u_%u_%s",
+ info->pdata->num, sh532u_gpios[i].label);
+ err = gpio_request_one(info->gpio[type].gpio, flags, label);
+ if (err) {
+ dev_err(&info->i2c_client->dev, "%s ERR %s %u\n",
+ __func__, label, info->gpio[type].gpio);
+ } else {
+ info->gpio[type].own = true;
+ dev_dbg(&info->i2c_client->dev, "%s %s %u\n",
+ __func__, label, info->gpio[type].gpio);
+ }
+ }
+}
+
+static int sh532u_vreg_dis(struct sh532u_info *info,
+ enum sh532u_vreg i)
{
int err = 0;
- sreg->vreg_flag = 0;
- sreg->vreg = regulator_get(&info->i2c_client->dev, vreg_name);
- if (IS_ERR_OR_NULL(sreg->vreg)) {
- dev_err(&info->i2c_client->dev,
- "%s err for regulator: %s err: %d\n",
- __func__, vreg_name, (int)sreg->vreg);
- err = PTR_ERR(sreg->vreg);
- sreg->vreg = NULL;
- } else {
- sreg->vreg_name = vreg_name;
- dev_dbg(&info->i2c_client->dev,
- "%s vreg_name: %s\n",
- __func__, sreg->vreg_name);
+ if (info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) {
+ err = regulator_disable(info->vreg[i].vreg);
+ if (!err)
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, info->vreg[i].vreg_name);
+ else
+ dev_err(&info->i2c_client->dev, "%s %s ERR\n",
+ __func__, info->vreg[i].vreg_name);
}
+ info->vreg[i].vreg_flag = false;
return err;
}
-static int sh532u_pm_regulator_en(struct sh532u_info *info,
- struct nvc_regulator *sreg)
+static int sh532u_vreg_dis_all(struct sh532u_info *info)
{
+ unsigned i;
int err = 0;
- if (!sreg->vreg_flag && (sreg->vreg != NULL)) {
- err = regulator_enable(sreg->vreg);
+ for (i = ARRAY_SIZE(sh532u_vregs); i > 0; i--)
+ err |= sh532u_vreg_dis(info, (i - 1));
+ return err;
+}
+
+static int sh532u_vreg_en(struct sh532u_info *info,
+ enum sh532u_vreg i)
+{
+ int err = 0;
+
+ if (!info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) {
+ err = regulator_enable(info->vreg[i].vreg);
if (!err) {
- dev_dbg(&info->i2c_client->dev,
- "%s vreg_name: %s\n",
- __func__, sreg->vreg_name);
- sreg->vreg_flag = 1;
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, info->vreg[i].vreg_name);
+ info->vreg[i].vreg_flag = true;
err = 1; /* flag regulator state change */
} else {
- dev_err(&info->i2c_client->dev,
- "%s err, regulator: %s\n",
- __func__, sreg->vreg_name);
+ dev_err(&info->i2c_client->dev, "%s %s ERR\n",
+ __func__, info->vreg[i].vreg_name);
}
}
return err;
}
-static int sh532u_pm_regulator_dis(struct sh532u_info *info,
- struct nvc_regulator *sreg)
+static int sh532u_vreg_en_all(struct sh532u_info *info)
{
+ unsigned i;
int err = 0;
- if (sreg->vreg_flag && (sreg->vreg != NULL)) {
- err = regulator_disable(sreg->vreg);
- if (err)
- dev_err(&info->i2c_client->dev,
- "%s err, regulator: %s\n",
- __func__, sreg->vreg_name);
+ for (i = 0; i < ARRAY_SIZE(sh532u_vregs); i++)
+ err |= sh532u_vreg_en(info, i);
+ return err;
+}
+
+static void sh532u_vreg_exit(struct sh532u_info *info)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(sh532u_vregs); i++) {
+ regulator_put(info->vreg[i].vreg);
+ info->vreg[i].vreg = NULL;
+ }
+}
+
+static int sh532u_vreg_init(struct sh532u_info *info)
+{
+ unsigned i;
+ unsigned j;
+ int err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sh532u_vregs); i++) {
+ j = sh532u_vregs[i].vreg_num;
+ info->vreg[j].vreg_name = sh532u_vregs[i].vreg_name;
+ info->vreg[j].vreg_flag = false;
+ info->vreg[j].vreg = regulator_get(&info->i2c_client->dev,
+ info->vreg[j].vreg_name);
+ if (IS_ERR_OR_NULL(info->vreg[j].vreg)) {
+ if (PTR_ERR(info->vreg[j].vreg) != -ENODEV)
+ dev_dbg(&info->i2c_client->dev,
+ "%s %s ERR: %d\n",
+ __func__, info->vreg[j].vreg_name,
+ (int)info->vreg[j].vreg);
+ else
+ dev_info(&info->i2c_client->dev,
+ "%s no regulator found for %s. "
+ "This board may not have an"
+ "independent %s regulator.\n",
+ __func__, info->vreg[j].vreg_name,
+ info->vreg[j].vreg_name);
+ err |= PTR_ERR(info->vreg[j].vreg);
+ info->vreg[j].vreg = NULL;
+ } else {
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, info->vreg[j].vreg_name);
+ }
}
- sreg->vreg_flag = 0;
return err;
}
@@ -402,17 +561,15 @@ static int sh532u_pm_wr(struct sh532u_info *info, int pwr)
switch (pwr) {
case NVC_PWR_OFF_FORCE:
case NVC_PWR_OFF:
- sh532u_gpio_en(info, 0);
- err = sh532u_pm_regulator_dis(info, &info->vreg_vdd);
- err |= sh532u_pm_regulator_dis(info, &info->vreg_i2c);
+ err = sh532u_vreg_dis_all(info);
+ sh532u_gpio_able(info, 0);
sh532u_gpio_reset(info, 0);
break;
case NVC_PWR_STDBY_OFF:
case NVC_PWR_STDBY:
- err = sh532u_pm_regulator_en(info, &info->vreg_vdd);
- err |= sh532u_pm_regulator_en(info, &info->vreg_i2c);
- sh532u_gpio_en(info, 1);
+ err = sh532u_vreg_en_all(info);
+ sh532u_gpio_able(info, 1);
sh532u_gpio_reset(info, 1);
err |= sh532u_i2c_wr8(info, STBY_211, 0x80);
err |= sh532u_i2c_wr8(info, CLKSEL_211, 0x38);
@@ -421,9 +578,8 @@ static int sh532u_pm_wr(struct sh532u_info *info, int pwr)
case NVC_PWR_COMM:
case NVC_PWR_ON:
- err = sh532u_pm_regulator_en(info, &info->vreg_vdd);
- err |= sh532u_pm_regulator_en(info, &info->vreg_i2c);
- sh532u_gpio_en(info, 1);
+ err = sh532u_vreg_en_all(info);
+ sh532u_gpio_able(info, 1);
sh532u_gpio_reset(info, 1);
err |= sh532u_i2c_wr8(info, CLKSEL_211, 0x38);
err |= sh532u_i2c_wr8(info, CLKSEL_211, 0x34);
@@ -436,11 +592,12 @@ static int sh532u_pm_wr(struct sh532u_info *info, int pwr)
}
if (err < 0) {
- dev_err(&info->i2c_client->dev, "%s pwr err: %d\n",
- __func__, pwr);
+ dev_err(&info->i2c_client->dev, "%s err %d\n", __func__, err);
pwr = NVC_PWR_ERR;
}
info->pwr_dev = pwr;
+ dev_dbg(&info->i2c_client->dev, "%s pwr_dev=%d\n",
+ __func__, info->pwr_dev);
if (err > 0)
return 0;
@@ -493,31 +650,58 @@ static int sh532u_pm_dev_wr(struct sh532u_info *info, int pwr)
static void sh532u_pm_exit(struct sh532u_info *info)
{
sh532u_pm_wr(info, NVC_PWR_OFF_FORCE);
- sh532u_pm_regulator_put(&info->vreg_vdd);
- sh532u_pm_regulator_put(&info->vreg_i2c);
- if (info->s_info != NULL) {
- sh532u_pm_wr(info->s_info, NVC_PWR_OFF_FORCE);
- sh532u_pm_regulator_put(&info->s_info->vreg_vdd);
- sh532u_pm_regulator_put(&info->s_info->vreg_i2c);
- }
+ sh532u_vreg_exit(info);
+ sh532u_gpio_exit(info);
}
static void sh532u_pm_init(struct sh532u_info *info)
{
- sh532u_pm_regulator_get(info, &info->vreg_vdd, "vdd");
- sh532u_pm_regulator_get(info, &info->vreg_i2c, "vdd_i2c");
+ sh532u_gpio_init(info);
+ sh532u_vreg_init(info);
+}
+
+static int sh532u_reset(struct sh532u_info *info, u32 level)
+{
+ int err;
+
+ if (level == NVC_RESET_SOFT) {
+ err = sh532u_pm_wr(info, NVC_PWR_COMM);
+ err |= sh532u_i2c_wr8(info, SFTRST_211, 0xFF); /* SW reset */
+ mdelay(1);
+ err |= sh532u_i2c_wr8(info, SFTRST_211, 0);
+ } else {
+ err = sh532u_pm_wr(info, NVC_PWR_OFF_FORCE);
+ }
+ err |= sh532u_pm_wr(info, info->pwr_api);
+ return err;
}
static int sh532u_dev_id(struct sh532u_info *info)
{
- u8 val;
+ u8 val = 0;
+ unsigned i;
int err;
+ sh532u_pm_dev_wr(info, NVC_PWR_COMM);
err = sh532u_i2c_rd8(info, 0, HVCA_DEVICE_ID, &val);
- if (!err && (val == SH532U_ID))
- return 0;
-
- return -ENODEV;
+ if (!err) {
+ dev_dbg(&info->i2c_client->dev, "%s found devId: %x\n",
+ __func__, val);
+ info->id_minor = 0;
+ for (i = 0; i < ARRAY_SIZE(sh532u_ids); i++) {
+ if (val == sh532u_ids[i]) {
+ info->id_minor = val;
+ break;
+ }
+ }
+ if (!info->id_minor) {
+ err = -ENODEV;
+ dev_dbg(&info->i2c_client->dev, "%s No devId match\n",
+ __func__);
+ }
+ }
+ sh532u_pm_dev_wr(info, NVC_PWR_OFF);
+ return err;
}
static void sh532u_sts_rd(struct sh532u_info *info)
@@ -633,9 +817,8 @@ static int sh532u_rel_pos_rd(struct sh532u_info *info, u32 *position)
return 0;
}
-static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
+static void sh532u_calibration_caps(struct sh532u_info *info)
{
- u8 reg;
s16 abs_top;
u32 rel_range;
u32 rel_lo;
@@ -643,45 +826,75 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
u32 step;
u32 loop_limit;
u32 i;
+
+ /*
+ * calculate relative and absolute positions
+ * Note that relative values, what upper SW uses, are the
+ * abstraction of HW (absolute) values.
+ * |<--limit_low limit_high-->|
+ * | |<-------------------_ACTUATOR_RANGE------------------->| |
+ * -focus_inf -focus_mac
+ * |<---RI--->| |<---RM--->|
+ * -abs_base -pos_low -pos_high -abs_top
+ *
+ * The pos_low and pos_high are fixed absolute positions and correspond
+ * to the relative focus_infinity and focus_macro, respectively. We'd
+ * like to have "wiggle" room (RI and RM) around these relative
+ * positions so the loop below finds the best fit for RI and RM without
+ * passing the absolute limits.
+ * We want our _ACTUATOR_RANGE to be infinity on the 0 end and macro
+ * on the max end. However, the focuser HW is opposite this.
+ * Therefore we use the rel(ative)_lo/hi variables in the calculation
+ * loop and assign them the focus_infinity and focus_macro values.
+ */
+ rel_lo = (info->cap.actuator_range - info->cap.focus_macro);
+ rel_hi = info->cap.focus_infinity;
+ info->abs_range = (u32)(info->cfg.pos_high - info->cfg.pos_low);
+ loop_limit = (rel_lo > rel_hi) ? rel_lo : rel_hi;
+ for (i = 0; i <= loop_limit; i++) {
+ rel_range = info->cap.actuator_range - (rel_lo + rel_hi);
+ step = info->abs_range / rel_range;
+ info->abs_base = info->cfg.pos_low - (step * rel_lo);
+ abs_top = info->cfg.pos_high + (step * rel_hi);
+ if (info->abs_base < info->cfg.limit_low) {
+ if (rel_lo > 0)
+ rel_lo--;
+ }
+ if (abs_top > info->cfg.limit_high) {
+ if (rel_hi > 0)
+ rel_hi--;
+ }
+ if (info->abs_base >= info->cfg.limit_low &&
+ abs_top <= info->cfg.limit_high)
+ break;
+ }
+ info->cap.focus_hyper = info->abs_range;
+ info->abs_range = (u32)(abs_top - info->abs_base);
+ /* calculate absolute hyperfocus position */
+ info->cap.focus_hyper *= info->cfg.focus_hyper_ratio;
+ info->cap.focus_hyper /= info->cfg.focus_hyper_div;
+ abs_top = (s16)(info->cfg.pos_high - info->cap.focus_hyper);
+ /* update actual relative positions */
+ info->cap.focus_hyper = sh532u_abs2rel(info, abs_top);
+ info->cap.focus_infinity = sh532u_abs2rel(info, info->cfg.pos_high);
+ info->cap.focus_macro = sh532u_abs2rel(info, info->cfg.pos_low);
+ dev_dbg(&info->i2c_client->dev, "%s focus_macro=%u\n",
+ __func__, info->cap.focus_macro);
+ dev_dbg(&info->i2c_client->dev, "%s focus_infinity=%u\n",
+ __func__, info->cap.focus_infinity);
+ dev_dbg(&info->i2c_client->dev, "%s focus_hyper=%u\n",
+ __func__, info->cap.focus_hyper);
+}
+
+static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
+{
+ u8 reg;
int err;
int ret = 0;
if (info->init_cal_flag)
return 0;
- /* set defaults */
- memcpy(&info->cfg, &sh532u_default_info, sizeof(info->cfg));
- memcpy(&info->nvc, &sh532u_default_nvc, sizeof(info->nvc));
- memcpy(&info->cap, &sh532u_default_cap, sizeof(info->cap));
- if (info->pdata->i2c_addr_rom)
- info->i2c_addr_rom = info->pdata->i2c_addr_rom;
- else
- info->i2c_addr_rom = sh532u_default_pdata.i2c_addr_rom;
- /* set overrides if any */
- if (info->pdata->nvc) {
- if (info->pdata->nvc->fnumber)
- info->nvc.fnumber = info->pdata->nvc->fnumber;
- if (info->pdata->nvc->focal_length)
- info->nvc.focal_length =
- info->pdata->nvc->focal_length;
- if (info->pdata->nvc->max_aperature)
- info->nvc.max_aperature =
- info->pdata->nvc->max_aperature;
- }
- if (info->pdata->cap) {
- if (info->pdata->cap->actuator_range)
- info->cap.actuator_range =
- info->pdata->cap->actuator_range;
- if (info->pdata->cap->settle_time)
- info->cap.settle_time = info->pdata->cap->settle_time;
- if (info->pdata->cap->focus_macro)
- info->cap.focus_macro = info->pdata->cap->focus_macro;
- if (info->pdata->cap->focus_hyper)
- info->cap.focus_hyper = info->pdata->cap->focus_hyper;
- if (info->pdata->cap->focus_infinity)
- info->cap.focus_infinity =
- info->pdata->cap->focus_infinity;
- }
/*
* Get Inf1, Mac1
* Inf1 and Mac1 are the mechanical limit position.
@@ -770,78 +983,22 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
info->cfg.limit_low = SH532U_POS_LOW_DEFAULT;
info->cfg.limit_high = SH532U_POS_HIGH_DEFAULT;
dev_err(&info->i2c_client->dev, "%s ERR: ERPOM data is void! "
- "Focuser will use defaults that will cause "
- "reduced functionality!\n", __func__);
+ "Focuser will use defaults that will cause "
+ "reduced functionality!\n", __func__);
}
if (info->cfg.pos_low < info->cfg.limit_low)
info->cfg.pos_low = info->cfg.limit_low;
if (info->cfg.pos_high > info->cfg.limit_high)
info->cfg.pos_high = info->cfg.limit_high;
- dev_dbg(&info->i2c_client->dev, "%s pos_low=%d\n", __func__,
- (int)info->cfg.pos_low);
- dev_dbg(&info->i2c_client->dev, "%s pos_high=%d\n", __func__,
- (int)info->cfg.pos_high);
- dev_dbg(&info->i2c_client->dev, "%s limit_low=%d\n", __func__,
- (int)info->cfg.limit_low);
- dev_dbg(&info->i2c_client->dev, "%s limit_high=%d\n", __func__,
- (int)info->cfg.limit_high);
- /*
- * calculate relative and absolute positions
- * Note that relative values, what upper SW uses, are the
- * abstraction of HW (absolute) values.
- * |<--limit_low limit_high-->|
- * | |<-------------------_ACTUATOR_RANGE------------------->| |
- * -focus_inf -focus_mac
- * |<---RI--->| |<---RM--->|
- * -abs_base -pos_low -pos_high -abs_top
- *
- * The pos_low and pos_high are fixed absolute positions and correspond
- * to the relative focus_infinity and focus_macro, respectively. We'd
- * like to have "wiggle" room (RI and RM) around these relative
- * positions so the loop below finds the best fit for RI and RM without
- * passing the absolute limits.
- * We want our _ACTUATOR_RANGE to be infinity on the 0 end and macro
- * on the max end. However, the focuser HW is opposite this.
- * Therefore we use the rel(ative)_lo/hi variables in the calculation
- * loop and assign them the focus_infinity and focus_macro values.
- */
- rel_lo = (info->cap.actuator_range - info->cap.focus_macro);
- rel_hi = info->cap.focus_infinity;
- info->abs_range = (u32)(info->cfg.pos_high - info->cfg.pos_low);
- loop_limit = (rel_lo > rel_hi) ? rel_lo : rel_hi;
- for (i = 0; i <= loop_limit; i++) {
- rel_range = info->cap.actuator_range - (rel_lo + rel_hi);
- step = info->abs_range / rel_range;
- info->abs_base = info->cfg.pos_low - (step * rel_lo);
- abs_top = info->cfg.pos_high + (step * rel_hi);
- if (info->abs_base < info->cfg.limit_low) {
- if (rel_lo > 0)
- rel_lo--;
- }
- if (abs_top > info->cfg.limit_high) {
- if (rel_hi > 0)
- rel_hi--;
- }
- if (info->abs_base >= info->cfg.limit_low &&
- abs_top <= info->cfg.limit_high)
- break;
- }
- info->cap.focus_hyper = info->abs_range;
- info->abs_range = (u32)(abs_top - info->abs_base);
- /* calculate absolute hyperfocus position */
- info->cap.focus_hyper *= info->cfg.focus_hyper_ratio;
- info->cap.focus_hyper /= info->cfg.focus_hyper_div;
- abs_top = (s16)(info->cfg.pos_high - info->cap.focus_hyper);
- /* update actual relative positions */
- info->cap.focus_hyper = sh532u_abs2rel(info, abs_top);
- info->cap.focus_infinity = sh532u_abs2rel(info, info->cfg.pos_high);
- info->cap.focus_macro = sh532u_abs2rel(info, info->cfg.pos_low);
- dev_dbg(&info->i2c_client->dev, "%s focus_macro=%u\n", __func__,
- info->cap.focus_macro);
- dev_dbg(&info->i2c_client->dev, "%s focus_infinity=%u\n", __func__,
- info->cap.focus_infinity);
- dev_dbg(&info->i2c_client->dev, "%s focus_hyper=%u\n", __func__,
- info->cap.focus_hyper);
+ dev_dbg(&info->i2c_client->dev, "%s pos_low=%d\n",
+ __func__, (int)info->cfg.pos_low);
+ dev_dbg(&info->i2c_client->dev, "%s pos_high=%d\n",
+ __func__, (int)info->cfg.pos_high);
+ dev_dbg(&info->i2c_client->dev, "%s limit_low=%d\n",
+ __func__, (int)info->cfg.limit_low);
+ dev_dbg(&info->i2c_client->dev, "%s limit_high=%d\n",
+ __func__, (int)info->cfg.limit_high);
+ sh532u_calibration_caps(info);
info->init_cal_flag = 1;
dev_dbg(&info->i2c_client->dev, "%s complete\n", __func__);
return 0;
@@ -955,6 +1112,9 @@ static int sh532u_dev_init(struct sh532u_info *info)
int ret = 0;
err = sh532u_i2c_rd8(info, 0, SWTCH_211, &ep_data1);
+ if (err)
+ return err; /* exit if unable to communicate with device */
+
ep_data2 = ep_data1;
err |= sh532u_i2c_rd8(info, 0, ANA1_211, &ep_data1);
ep_data2 |= ep_data1;
@@ -1007,7 +1167,7 @@ static int sh532u_dev_init(struct sh532u_info *info)
err = ret;
if (err)
dev_err(&info->i2c_client->dev, "%s programming err=%d\n",
- __func__, err);
+ __func__, err);
err |= sh532u_calibration(info, false);
info->sts = NVC_FOCUS_STS_LENS_SETTLED;
return err;
@@ -1031,7 +1191,7 @@ static int sh532u_pos_abs_wr(struct sh532u_info *info, s16 tar_pos)
return err;
dev_dbg(&info->i2c_client->dev, "%s cur_pos=%d tar_pos=%d\n",
- __func__, (int)cur_pos, (int)tar_pos);
+ __func__, (int)cur_pos, (int)tar_pos);
info->sts = NVC_FOCUS_STS_WAIT_FOR_MOVE_END;
/* Check move distance to Target Position */
move_distance = abs((int)cur_pos - (int)tar_pos);
@@ -1135,7 +1295,7 @@ static int sh532u_pos_rel_wr(struct sh532u_info *info, u32 position)
if (position > info->cap.actuator_range) {
dev_err(&info->i2c_client->dev, "%s invalid position %u\n",
- __func__, position);
+ __func__, position);
return -EINVAL;
}
@@ -1159,7 +1319,7 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
(const void __user *)arg,
sizeof(struct nvc_param))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
- __func__, __LINE__);
+ __func__, __LINE__);
return -EFAULT;
}
@@ -1176,28 +1336,28 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
data_size = sizeof(position);
sh532u_pm_dev_wr(info, NVC_PWR_STDBY);
dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n",
- __func__, position);
+ __func__, position);
break;
case NVC_PARAM_FOCAL_LEN:
data_ptr = &info->nvc.focal_length;
data_size = sizeof(info->nvc.focal_length);
dev_dbg(&info->i2c_client->dev, "%s FOCAL_LEN: %x\n",
- __func__, info->nvc.focal_length);
+ __func__, info->nvc.focal_length);
break;
case NVC_PARAM_MAX_APERTURE:
data_ptr = &info->nvc.max_aperature;
data_size = sizeof(info->nvc.max_aperature);
dev_dbg(&info->i2c_client->dev, "%s MAX_APERTURE: %x\n",
- __func__, info->nvc.max_aperature);
+ __func__, info->nvc.max_aperature);
break;
case NVC_PARAM_FNUMBER:
data_ptr = &info->nvc.fnumber;
data_size = sizeof(info->nvc.fnumber);
- dev_dbg(&info->i2c_client->dev, "%s FNUMBER: %x\n",
- __func__, info->nvc.fnumber);
+ dev_dbg(&info->i2c_client->dev, "%s FNUMBER: %u\n",
+ __func__, info->nvc.fnumber);
break;
case NVC_PARAM_CAPS:
@@ -1215,41 +1375,42 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
else
data_size = sizeof(info->cap);
dev_dbg(&info->i2c_client->dev, "%s CAPS\n",
- __func__);
+ __func__);
break;
case NVC_PARAM_STS:
data_ptr = &info->sts;
data_size = sizeof(info->sts);
dev_dbg(&info->i2c_client->dev, "%s STS: %d\n",
- __func__, info->sts);
+ __func__, info->sts);
break;
case NVC_PARAM_STEREO:
data_ptr = &info->s_mode;
data_size = sizeof(info->s_mode);
dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n",
- __func__, info->s_mode);
+ __func__, info->s_mode);
break;
default:
- dev_err(&info->i2c_client->dev,
- "%s unsupported parameter: %d\n",
- __func__, params.param);
+ dev_dbg(&info->i2c_client->dev,
+ "%s unsupported parameter: %d\n",
+ __func__, params.param);
return -EINVAL;
}
if (params.sizeofvalue < data_size) {
- dev_err(&info->i2c_client->dev, "%s %d data size err\n",
- __func__, __LINE__);
+ dev_err(&info->i2c_client->dev,
+ "%s data size mismatch %d != %d Param: %d\n",
+ __func__, params.sizeofvalue, data_size, params.param);
return -EINVAL;
}
if (copy_to_user((void __user *)params.p_value,
data_ptr,
data_size)) {
- dev_err(&info->i2c_client->dev, "%s %d copy_to_user err\n",
- __func__, __LINE__);
+ dev_err(&info->i2c_client->dev,
+ "%s copy_to_user err line %d\n", __func__, __LINE__);
return -EFAULT;
}
@@ -1258,35 +1419,59 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
static int sh532u_param_wr_s(struct sh532u_info *info,
struct nvc_param *params,
- u32 u32_val)
+ u32 u32val)
{
+ struct nvc_focus_cap cap;
+ u8 u8val;
int err;
+ u8val = (u8)u32val;
switch (params->param) {
case NVC_PARAM_LOCUS:
dev_dbg(&info->i2c_client->dev, "%s LOCUS: %u\n",
- __func__, u32_val);
- err = sh532u_pos_rel_wr(info, u32_val);
+ __func__, u32val);
+ err = sh532u_pos_rel_wr(info, u32val);
return err;
case NVC_PARAM_RESET:
- err = sh532u_pm_wr(info, NVC_PWR_OFF);
- err |= sh532u_pm_wr(info, NVC_PWR_ON);
- err |= sh532u_pm_wr(info, info->pwr_api);
+ err = sh532u_reset(info, u32val);
dev_dbg(&info->i2c_client->dev, "%s RESET: %d\n",
- __func__, err);
+ __func__, err);
return err;
case NVC_PARAM_SELF_TEST:
err = sh532u_hvca_pos_init(info);
dev_dbg(&info->i2c_client->dev, "%s SELF_TEST: %d\n",
- __func__, err);
+ __func__, err);
return err;
+ case NVC_PARAM_CAPS:
+ dev_dbg(&info->i2c_client->dev, "%s CAPS\n",
+ __func__);
+ if (copy_from_user(&cap, (const void __user *)params->p_value,
+ sizeof(params->sizeofvalue))) {
+ dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ if (!cap.version)
+ return -EINVAL;
+
+ if (cap.version >= NVC_FOCUS_CAP_VER1)
+ info->cap.actuator_range = cap.actuator_range;
+ if (cap.version >= NVC_FOCUS_CAP_VER2) {
+ info->cap.focus_macro = cap.focus_macro;
+ info->cap.focus_hyper = cap.focus_hyper;
+ info->cap.focus_infinity = cap.focus_infinity;
+ }
+ sh532u_calibration_caps(info);
+ return 0;
+
default:
- dev_err(&info->i2c_client->dev,
- "%s unsupported parameter: %d\n",
- __func__, params->param);
+ dev_dbg(&info->i2c_client->dev,
+ "%s unsupported parameter: %d\n",
+ __func__, params->param);
return -EINVAL;
}
}
@@ -1294,47 +1479,48 @@ static int sh532u_param_wr_s(struct sh532u_info *info,
static int sh532u_param_wr(struct sh532u_info *info, unsigned long arg)
{
struct nvc_param params;
- u8 val;
- u32 u32_val;
+ u8 u8val;
+ u32 u32val;
int err = 0;
- if (copy_from_user(&params,
- (const void __user *)arg,
- sizeof(struct nvc_param))) {
- dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
- __func__, __LINE__);
+ if (copy_from_user(&params, (const void __user *)arg,
+ sizeof(struct nvc_param))) {
+ dev_err(&info->i2c_client->dev,
+ "%s copy_from_user err line %d\n", __func__, __LINE__);
return -EFAULT;
}
- if (copy_from_user(&u32_val, (const void __user *)params.p_value,
- sizeof(u32_val))) {
+ if (copy_from_user(&u32val, (const void __user *)params.p_value,
+ sizeof(u32val))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
- __func__, __LINE__);
+ __func__, __LINE__);
return -EFAULT;
}
+ u8val = (u8)u32val;
/* parameters independent of sync mode */
switch (params.param) {
case NVC_PARAM_STEREO:
- dev_dbg(&info->i2c_client->dev, "%s STEREO: %u\n",
- __func__, u32_val);
- val = (u8)u32_val;
- if (val == info->s_mode)
+ dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n",
+ __func__, u8val);
+ if (u8val == info->s_mode)
return 0;
- switch (val) {
+ switch (u8val) {
case NVC_SYNC_OFF:
- info->s_mode = val;
+ info->s_mode = u8val;
+ sh532u_gpio_wr(info, SH532U_GPIO_I2CMUX, 0);
if (info->s_info != NULL) {
- info->s_info->s_mode = val;
+ info->s_info->s_mode = u8val;
sh532u_pm_wr(info->s_info, NVC_PWR_OFF);
}
break;
case NVC_SYNC_MASTER:
- info->s_mode = val;
+ info->s_mode = u8val;
+ sh532u_gpio_wr(info, SH532U_GPIO_I2CMUX, 0);
if (info->s_info != NULL)
- info->s_info->s_mode = val;
+ info->s_info->s_mode = u8val;
break;
case NVC_SYNC_SLAVE:
@@ -1343,8 +1529,10 @@ static int sh532u_param_wr(struct sh532u_info *info, unsigned long arg)
err = sh532u_pos_rel_wr(info->s_info,
info->s_info->cap.focus_infinity);
if (!err) {
- info->s_mode = val;
- info->s_info->s_mode = val;
+ info->s_mode = u8val;
+ info->s_info->s_mode = u8val;
+ sh532u_gpio_wr(info,
+ SH532U_GPIO_I2CMUX, 0);
} else {
if (info->s_mode != NVC_SYNC_STEREO)
sh532u_pm_wr(info->s_info,
@@ -1364,8 +1552,10 @@ static int sh532u_param_wr(struct sh532u_info *info, unsigned long arg)
err = sh532u_pos_rel_wr(info->s_info,
info->pos_rel);
if (!err) {
- info->s_mode = val;
- info->s_info->s_mode = val;
+ info->s_mode = u8val;
+ info->s_info->s_mode = u8val;
+ sh532u_gpio_wr(info,
+ SH532U_GPIO_I2CMUX, 1);
} else {
if (info->s_mode != NVC_SYNC_SLAVE)
sh532u_pm_wr(info->s_info,
@@ -1390,49 +1580,52 @@ static int sh532u_param_wr(struct sh532u_info *info, unsigned long arg)
switch (info->s_mode) {
case NVC_SYNC_OFF:
case NVC_SYNC_MASTER:
- return sh532u_param_wr_s(info, &params, u32_val);
+ return sh532u_param_wr_s(info, &params, u32val);
case NVC_SYNC_SLAVE:
- return sh532u_param_wr_s(info->s_info,
- &params,
- u32_val);
+ return sh532u_param_wr_s(info->s_info, &params,
+ u32val);
case NVC_SYNC_STEREO:
- err = sh532u_param_wr_s(info, &params, u32_val);
+ err = sh532u_param_wr_s(info, &params, u32val);
if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
err |= sh532u_param_wr_s(info->s_info,
&params,
- u32_val);
+ u32val);
return err;
default:
dev_err(&info->i2c_client->dev, "%s %d internal err\n",
- __func__, __LINE__);
+ __func__, __LINE__);
return -EINVAL;
}
}
}
static long sh532u_ioctl(struct file *file,
- unsigned int cmd,
- unsigned long arg)
+ unsigned int cmd,
+ unsigned long arg)
{
struct sh532u_info *info = file->private_data;
int pwr;
+ int err;
switch (cmd) {
case NVC_IOCTL_PARAM_WR:
- return sh532u_param_wr(info, arg);
+ err = sh532u_param_wr(info, arg);
+ return err;
case NVC_IOCTL_PARAM_RD:
- return sh532u_param_rd(info, arg);
+ err = sh532u_param_rd(info, arg);
+ return err;
case NVC_IOCTL_PWR_WR:
/* This is a Guaranteed Level of Service (GLOS) call */
pwr = (int)arg * 2;
- dev_dbg(&info->i2c_client->dev, "%s PWR: %d\n",
- __func__, pwr);
- return sh532u_pm_api_wr(info, pwr);
+ dev_dbg(&info->i2c_client->dev, "%s PWR_WR: %d\n",
+ __func__, pwr);
+ err = sh532u_pm_api_wr(info, pwr);
+ return err;
case NVC_IOCTL_PWR_RD:
if (info->s_mode == NVC_SYNC_SLAVE)
@@ -1440,7 +1633,7 @@ static long sh532u_ioctl(struct file *file,
else
pwr = info->pwr_api / 2;
dev_dbg(&info->i2c_client->dev, "%s PWR_RD: %d\n",
- __func__, pwr);
+ __func__, pwr);
if (copy_to_user((void __user *)arg, (const void *)&pwr,
sizeof(pwr))) {
dev_err(&info->i2c_client->dev,
@@ -1452,46 +1645,84 @@ static long sh532u_ioctl(struct file *file,
return 0;
default:
- dev_err(&info->i2c_client->dev, "%s unsupported ioctl: %x\n",
- __func__, cmd);
- return -EINVAL;
+ dev_dbg(&info->i2c_client->dev, "%s unsupported ioctl: %x\n",
+ __func__, cmd);
}
+
+ return -EINVAL;
}
-static int sh532u_sync_en(int dev1, int dev2)
+static void sh532u_sdata_init(struct sh532u_info *info)
{
- struct sh532u_info *sync1 = NULL;
- struct sh532u_info *sync2 = NULL;
+ /* set defaults */
+ memcpy(&info->cfg, &sh532u_default_info, sizeof(info->cfg));
+ memcpy(&info->nvc, &sh532u_default_nvc, sizeof(info->nvc));
+ memcpy(&info->cap, &sh532u_default_cap, sizeof(info->cap));
+ if (info->pdata->i2c_addr_rom)
+ info->i2c_addr_rom = info->pdata->i2c_addr_rom;
+ else
+ info->i2c_addr_rom = sh532u_default_pdata.i2c_addr_rom;
+ /* set overrides if any */
+ if (info->pdata->nvc) {
+ if (info->pdata->nvc->fnumber)
+ info->nvc.fnumber = info->pdata->nvc->fnumber;
+ if (info->pdata->nvc->focal_length)
+ info->nvc.focal_length =
+ info->pdata->nvc->focal_length;
+ if (info->pdata->nvc->max_aperature)
+ info->nvc.max_aperature =
+ info->pdata->nvc->max_aperature;
+ }
+ if (info->pdata->cap) {
+ if (info->pdata->cap->actuator_range)
+ info->cap.actuator_range =
+ info->pdata->cap->actuator_range;
+ if (info->pdata->cap->settle_time)
+ info->cap.settle_time = info->pdata->cap->settle_time;
+ if (info->pdata->cap->focus_macro)
+ info->cap.focus_macro = info->pdata->cap->focus_macro;
+ if (info->pdata->cap->focus_hyper)
+ info->cap.focus_hyper = info->pdata->cap->focus_hyper;
+ if (info->pdata->cap->focus_infinity)
+ info->cap.focus_infinity =
+ info->pdata->cap->focus_infinity;
+ }
+}
+
+static int sh532u_sync_en(unsigned num, unsigned sync)
+{
+ struct sh532u_info *master = NULL;
+ struct sh532u_info *slave = NULL;
struct sh532u_info *pos = NULL;
rcu_read_lock();
list_for_each_entry_rcu(pos, &sh532u_info_list, list) {
- if (pos->pdata->num == dev1) {
- sync1 = pos;
+ if (pos->pdata->num == num) {
+ master = pos;
break;
}
}
pos = NULL;
list_for_each_entry_rcu(pos, &sh532u_info_list, list) {
- if (pos->pdata->num == dev2) {
- sync2 = pos;
+ if (pos->pdata->num == sync) {
+ slave = pos;
break;
}
}
rcu_read_unlock();
- if (sync1 != NULL)
- sync1->s_info = NULL;
- if (sync2 != NULL)
- sync2->s_info = NULL;
- if (!dev1 && !dev2)
- return 0; /* no err if default instance 0's used */
-
- if (dev1 == dev2)
+ if (master != NULL)
+ master->s_info = NULL;
+ if (slave != NULL)
+ slave->s_info = NULL;
+ if (!sync)
+ return 0; /* no err if sync disabled */
+
+ if (num == sync)
return -EINVAL; /* err if sync instance is itself */
- if ((sync1 != NULL) && (sync2 != NULL)) {
- sync1->s_info = sync2;
- sync2->s_info = sync1;
+ if ((master != NULL) && (slave != NULL)) {
+ master->s_info = slave;
+ slave->s_info = master;
}
return 0;
}
@@ -1529,8 +1760,8 @@ static int sh532u_open(struct inode *inode, struct file *file)
err = sh532u_sync_en(info->pdata->num, info->pdata->sync);
if (err == -EINVAL)
dev_err(&info->i2c_client->dev,
- "%s err: invalid num (%u) and sync (%u) instance\n",
- __func__, info->pdata->num, info->pdata->sync);
+ "%s err: invalid num (%u) and sync (%u) instance\n",
+ __func__, info->pdata->num, info->pdata->sync);
if (atomic_xchg(&info->in_use, 1))
return -EBUSY;
@@ -1542,10 +1773,11 @@ static int sh532u_open(struct inode *inode, struct file *file)
file->private_data = info;
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
sh532u_pos_rel_wr(info, info->cap.focus_infinity);
+ sh532u_pm_wr_s(info, NVC_PWR_OFF);
return 0;
}
-int sh532u_release(struct inode *inode, struct file *file)
+static int sh532u_release(struct inode *inode, struct file *file)
{
struct sh532u_info *info = file->private_data;
@@ -1569,6 +1801,9 @@ static const struct file_operations sh532u_fileops = {
static void sh532u_del(struct sh532u_info *info)
{
sh532u_pm_exit(info);
+ if ((info->s_mode == NVC_SYNC_SLAVE) ||
+ (info->s_mode == NVC_SYNC_STEREO))
+ sh532u_pm_exit(info->s_info);
sh532u_sync_dis(info);
spin_lock(&sh532u_spinlock);
list_del_rcu(&info->list);
@@ -1590,7 +1825,7 @@ static int sh532u_probe(
struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct sh532u_info *info = NULL;
+ struct sh532u_info *info;
char dname[16];
int err;
@@ -1607,8 +1842,7 @@ static int sh532u_probe(
} else {
info->pdata = &sh532u_default_pdata;
dev_dbg(&client->dev,
- "%s No platform data. Using defaults.\n",
- __func__);
+ "%s No platform data. Using defaults.\n", __func__);
}
i2c_set_clientdata(client, info);
INIT_LIST_HEAD(&info->list);
@@ -1616,24 +1850,27 @@ static int sh532u_probe(
list_add_rcu(&info->list, &sh532u_info_list);
spin_unlock(&sh532u_spinlock);
sh532u_pm_init(info);
- sh532u_pm_dev_wr(info, NVC_PWR_COMM);
- err = sh532u_dev_id(info);
- if (err < 0) {
- dev_err(&client->dev, "%s device not found\n", __func__);
- sh532u_pm_wr(info, NVC_PWR_OFF);
- if (info->pdata->cfg & NVC_CFG_NODEV) {
- sh532u_del(info);
- return -ENODEV;
- }
- } else {
- dev_dbg(&client->dev, "%s device found\n", __func__);
- sh532u_calibration(info, false);
- if (info->pdata->cfg & NVC_CFG_BOOT_INIT) {
- /* initial move causes full initialization */
- sh532u_pos_rel_wr(info, info->cap.focus_infinity);
+ sh532u_sdata_init(info);
+ if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) {
+ err = sh532u_dev_id(info);
+ if (err < 0) {
+ if (info->pdata->cfg & NVC_CFG_NODEV) {
+ sh532u_del(info);
+ return -ENODEV;
+ } else {
+ dev_err(&client->dev, "%s dev %x not found\n",
+ __func__, SH532U_ID);
+ }
} else {
- sh532u_pm_wr(info, NVC_PWR_OFF);
+ dev_dbg(&client->dev, "%s device found\n", __func__);
+ sh532u_pm_dev_wr(info, NVC_PWR_ON);
+ sh532u_calibration(info, false);
+ if (info->pdata->cfg & NVC_CFG_BOOT_INIT)
+ /* initial move causes full initialization */
+ sh532u_pos_rel_wr(info,
+ info->cap.focus_infinity);
}
+ sh532u_pm_dev_wr(info, NVC_PWR_OFF);
}
if (info->pdata->dev_name != 0)
@@ -1648,7 +1885,7 @@ static int sh532u_probe(
info->miscdev.minor = MISC_DYNAMIC_MINOR;
if (misc_register(&info->miscdev)) {
dev_err(&client->dev, "%s unable to register misc device %s\n",
- __func__, dname);
+ __func__, dname);
sh532u_del(info);
return -ENODEV;
}
diff --git a/drivers/media/video/tegra/soc380.c b/drivers/media/video/tegra/soc380.c
index 7f2c136..e002216 100644
--- a/drivers/media/video/tegra/soc380.c
+++ b/drivers/media/video/tegra/soc380.c
@@ -471,3 +471,4 @@ static void __exit soc380_exit(void)
module_init(soc380_init);
module_exit(soc380_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/tegra_camera.c b/drivers/media/video/tegra/tegra_camera.c
index e90b130..de0c662 100644
--- a/drivers/media/video/tegra/tegra_camera.c
+++ b/drivers/media/video/tegra/tegra_camera.c
@@ -48,7 +48,8 @@ struct tegra_camera_dev {
struct regulator *reg;
struct tegra_camera_clk_info info;
struct mutex tegra_camera_lock;
- int power_refcnt;
+ atomic_t in_use;
+ int power_on;
};
struct tegra_camera_block {
@@ -57,56 +58,47 @@ struct tegra_camera_block {
bool is_enabled;
};
-static int tegra_camera_enable_isp(struct tegra_camera_dev *dev)
+static int tegra_camera_enable_clk(struct tegra_camera_dev *dev)
{
- return clk_enable(dev->isp_clk);
-}
-
-static int tegra_camera_disable_isp(struct tegra_camera_dev *dev)
-{
- clk_disable(dev->isp_clk);
+ clk_enable(dev->vi_clk);
+ clk_enable(dev->vi_sensor_clk);
+ clk_enable(dev->csus_clk);
+
+ tegra_periph_reset_assert(dev->vi_clk);
+ udelay(2);
+ tegra_periph_reset_deassert(dev->vi_clk);
+
+ clk_enable(dev->isp_clk);
+ tegra_periph_reset_assert(dev->isp_clk);
+ udelay(2);
+ tegra_periph_reset_deassert(dev->isp_clk);
+
+ clk_enable(dev->csi_clk);
+ tegra_periph_reset_assert(dev->csi_clk);
+ udelay(2);
+ tegra_periph_reset_deassert(dev->csi_clk);
return 0;
}
-static int tegra_camera_enable_vi(struct tegra_camera_dev *dev)
-{
- int ret = 0;
-
- ret |= clk_enable(dev->vi_clk);
- ret |= clk_enable(dev->vi_sensor_clk);
- ret |= clk_enable(dev->csus_clk);
- return ret;
-}
-
-static int tegra_camera_disable_vi(struct tegra_camera_dev *dev)
+static int tegra_camera_disable_clk(struct tegra_camera_dev *dev)
{
- clk_disable(dev->vi_clk);
- clk_disable(dev->vi_sensor_clk);
+ clk_disable(dev->csi_clk);
+ tegra_periph_reset_assert(dev->csi_clk);
+ clk_disable(dev->isp_clk);
+ tegra_periph_reset_assert(dev->isp_clk);
clk_disable(dev->csus_clk);
- return 0;
-}
-
-static int tegra_camera_enable_csi(struct tegra_camera_dev *dev)
-{
- return clk_enable(dev->csi_clk);
-}
+ clk_disable(dev->vi_sensor_clk);
+ clk_disable(dev->vi_clk);
+ tegra_periph_reset_assert(dev->vi_clk);
-static int tegra_camera_disable_csi(struct tegra_camera_dev *dev)
-{
- clk_disable(dev->csi_clk);
return 0;
}
static int tegra_camera_enable_emc(struct tegra_camera_dev *dev)
{
- /* tegra_camera wasn't added as a user of emc_clk until 3x.
- set to 150 MHz, will likely need to be increased as we support
- sensors with higher framerates and resolutions. */
clk_enable(dev->emc_clk);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
clk_set_rate(dev->emc_clk, 300000000);
-#else
- clk_set_rate(dev->emc_clk, 150000000);
#endif
return 0;
}
@@ -117,32 +109,6 @@ static int tegra_camera_disable_emc(struct tegra_camera_dev *dev)
return 0;
}
-struct tegra_camera_block tegra_camera_block[] = {
- [TEGRA_CAMERA_MODULE_ISP] = {tegra_camera_enable_isp,
- tegra_camera_disable_isp, false},
- [TEGRA_CAMERA_MODULE_VI] = {tegra_camera_enable_vi,
- tegra_camera_disable_vi, false},
- [TEGRA_CAMERA_MODULE_CSI] = {tegra_camera_enable_csi,
- tegra_camera_disable_csi, false},
-};
-
-#define TEGRA_CAMERA_VI_CLK_SEL_INTERNAL 0
-#define TEGRA_CAMERA_VI_CLK_SEL_EXTERNAL (1<<24)
-#define TEGRA_CAMERA_PD2VI_CLK_SEL_VI_SENSOR_CLK (1<<25)
-#define TEGRA_CAMERA_PD2VI_CLK_SEL_PD2VI_CLK 0
-
-static bool tegra_camera_enabled(struct tegra_camera_dev *dev)
-{
- bool ret = false;
-
- mutex_lock(&dev->tegra_camera_lock);
- ret = tegra_camera_block[TEGRA_CAMERA_MODULE_ISP].is_enabled == true ||
- tegra_camera_block[TEGRA_CAMERA_MODULE_VI].is_enabled == true ||
- tegra_camera_block[TEGRA_CAMERA_MODULE_CSI].is_enabled == true;
- mutex_unlock(&dev->tegra_camera_lock);
- return ret;
-}
-
static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
{
struct clk *clk, *clk_parent;
@@ -156,7 +122,8 @@ static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
return -EINVAL;
}
- if (info->id != TEGRA_CAMERA_MODULE_VI) {
+ if (info->id != TEGRA_CAMERA_MODULE_VI &&
+ info->id != TEGRA_CAMERA_MODULE_EMC) {
dev_err(dev->dev,
"%s: set rate only aplies to vi module %d\n",
__func__, info->id);
@@ -170,6 +137,14 @@ static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
case TEGRA_CAMERA_VI_SENSOR_CLK:
clk = dev->vi_sensor_clk;
break;
+ case TEGRA_CAMERA_EMC_CLK:
+ clk = dev->emc_clk;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ dev_dbg(dev->dev, "%s: emc_clk rate=%lu\n",
+ __func__, info->rate);
+ clk_set_rate(dev->emc_clk, info->rate);
+#endif
+ goto set_rate_end;
default:
dev_err(dev->dev,
"%s: invalid clk id for set rate %d\n",
@@ -215,61 +190,39 @@ static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
#endif
}
+set_rate_end:
info->rate = clk_get_rate(clk);
dev_dbg(dev->dev, "%s: get_rate=%lu",
__func__, info->rate);
return 0;
}
-static int tegra_camera_reset(struct tegra_camera_dev *dev, uint id)
-{
- struct clk *clk;
-
- switch (id) {
- case TEGRA_CAMERA_MODULE_VI:
- clk = dev->vi_clk;
- break;
- case TEGRA_CAMERA_MODULE_ISP:
- clk = dev->isp_clk;
- break;
- case TEGRA_CAMERA_MODULE_CSI:
- clk = dev->csi_clk;
- break;
- default:
- return -EINVAL;
- }
- tegra_periph_reset_assert(clk);
- udelay(10);
- tegra_periph_reset_deassert(clk);
-
- return 0;
-}
static int tegra_camera_power_on(struct tegra_camera_dev *dev)
{
int ret = 0;
- if (dev->power_refcnt++ == 0) {
- /* Enable external power */
- if (dev->reg) {
- ret = regulator_enable(dev->reg);
- if (ret) {
- dev_err(dev->dev,
- "%s: enable csi regulator failed.\n",
- __func__);
- return ret;
- }
- }
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Unpowergate VE */
- ret = tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
- if (ret)
+ dev_dbg(dev->dev, "%s++\n", __func__);
+
+ /* Enable external power */
+ if (dev->reg) {
+ ret = regulator_enable(dev->reg);
+ if (ret) {
dev_err(dev->dev,
- "%s: unpowergate failed.\n",
+ "%s: enable csi regulator failed.\n",
__func__);
-#endif
+ return ret;
+ }
}
-
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ /* Unpowergate VE */
+ ret = tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
+ if (ret)
+ dev_err(dev->dev,
+ "%s: unpowergate failed.\n",
+ __func__);
+#endif
+ dev->power_on = 1;
return ret;
}
@@ -277,26 +230,27 @@ static int tegra_camera_power_off(struct tegra_camera_dev *dev)
{
int ret = 0;
- if (--dev->power_refcnt == 0) {
+ dev_dbg(dev->dev, "%s++\n", __func__);
+
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Powergate VE */
- ret = tegra_powergate_partition(TEGRA_POWERGATE_VENC);
- if (ret)
+ /* Powergate VE */
+ ret = tegra_powergate_partition(TEGRA_POWERGATE_VENC);
+ if (ret)
+ dev_err(dev->dev,
+ "%s: powergate failed.\n",
+ __func__);
+#endif
+ /* Disable external power */
+ if (dev->reg) {
+ ret = regulator_disable(dev->reg);
+ if (ret) {
dev_err(dev->dev,
- "%s: powergate failed.\n",
+ "%s: disable csi regulator failed.\n",
__func__);
-#endif
- /* Disable external power */
- if (dev->reg) {
- ret = regulator_disable(dev->reg);
- if (ret) {
- dev_err(dev->dev,
- "%s: disable csi regulator failed.\n",
- __func__);
- return ret;
- }
+ return ret;
}
}
+ dev->power_on = 0;
return ret;
}
@@ -313,7 +267,7 @@ static long tegra_camera_ioctl(struct file *file,
return -EFAULT;
}
- if (id >= ARRAY_SIZE(tegra_camera_block)) {
+ if (id >= TEGRA_CAMERA_MODULE_MAX) {
dev_err(dev->dev,
"%s: Invalid id to tegra isp ioctl%d\n",
__func__, id);
@@ -321,44 +275,15 @@ static long tegra_camera_ioctl(struct file *file,
}
switch (cmd) {
+ /*
+ * Clock enable/disable and reset should be handled in kernel.
+ * In order to support legacy code in user space, we don't remove
+ * these IOCTL.
+ */
case TEGRA_CAMERA_IOCTL_ENABLE:
- {
- int ret = 0;
-
- mutex_lock(&dev->tegra_camera_lock);
- /* Unpowergate camera blocks (vi, csi and isp)
- before enabling clocks */
- ret = tegra_camera_power_on(dev);
- if (ret) {
- dev->power_refcnt = 0;
- mutex_unlock(&dev->tegra_camera_lock);
- return ret;
- }
-
- if (!tegra_camera_block[id].is_enabled) {
- ret = tegra_camera_block[id].enable(dev);
- tegra_camera_block[id].is_enabled = true;
- }
- mutex_unlock(&dev->tegra_camera_lock);
- return ret;
- }
case TEGRA_CAMERA_IOCTL_DISABLE:
- {
- int ret = 0;
-
- mutex_lock(&dev->tegra_camera_lock);
- if (tegra_camera_block[id].is_enabled) {
- ret = tegra_camera_block[id].disable(dev);
- tegra_camera_block[id].is_enabled = false;
- }
- /* Powergate camera blocks (vi, csi and isp)
- after disabling all the clocks */
- if (!ret) {
- ret = tegra_camera_power_off(dev);
- }
- mutex_unlock(&dev->tegra_camera_lock);
- return ret;
- }
+ case TEGRA_CAMERA_IOCTL_RESET:
+ return 0;
case TEGRA_CAMERA_IOCTL_CLK_SET_RATE:
{
int ret;
@@ -380,8 +305,6 @@ static long tegra_camera_ioctl(struct file *file,
}
return 0;
}
- case TEGRA_CAMERA_IOCTL_RESET:
- return tegra_camera_reset(dev, id);
default:
dev_err(dev->dev,
"%s: Unknown tegra_camera ioctl.\n", __func__);
@@ -396,40 +319,58 @@ static int tegra_camera_open(struct inode *inode, struct file *file)
struct tegra_camera_dev *dev = container_of(miscdev,
struct tegra_camera_dev,
misc_dev);
+ int ret = 0;
+
dev_info(dev->dev, "%s\n", __func__);
- file->private_data = dev;
- tegra_camera_enable_emc(dev);
+ if (atomic_xchg(&dev->in_use, 1))
+ return -EBUSY;
- return 0;
+ file->private_data = dev;
+
+ mutex_lock(&dev->tegra_camera_lock);
+ /* turn on CSI regulator */
+ ret = tegra_camera_power_on(dev);
+ if (ret)
+ goto open_exit;
+ /* set EMC request */
+ ret = tegra_camera_enable_emc(dev);
+ if (ret)
+ goto open_exit;
+ /* enable camera HW clock */
+ ret = tegra_camera_enable_clk(dev);
+ if (ret)
+ goto open_exit;
+open_exit:
+ mutex_unlock(&dev->tegra_camera_lock);
+ return ret;
}
static int tegra_camera_release(struct inode *inode, struct file *file)
{
- int i, err;
+ int ret = 0;
struct tegra_camera_dev *dev = file->private_data;
dev_info(dev->dev, "%s\n", __func__);
- for (i = 0; i < ARRAY_SIZE(tegra_camera_block); i++)
- if (tegra_camera_block[i].is_enabled) {
- tegra_camera_block[i].disable(dev);
- tegra_camera_block[i].is_enabled = false;
- }
- /* If camera blocks are not powergated yet, do it now */
- if (dev->power_refcnt > 0) {
- mutex_lock(&dev->tegra_camera_lock);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- err = tegra_powergate_partition(TEGRA_POWERGATE_VENC);
- if (err)
- dev_err(dev->dev, "%s: powergate failed.\n", __func__);
-#endif
- dev->power_refcnt = 0;
- mutex_unlock(&dev->tegra_camera_lock);
- }
-
- tegra_camera_disable_emc(dev);
+ mutex_lock(&dev->tegra_camera_lock);
+ /* disable HW clock */
+ ret = tegra_camera_disable_clk(dev);
+ if (ret)
+ goto release_exit;
+ /* nullify EMC request */
+ ret = tegra_camera_disable_emc(dev);
+ if (ret)
+ goto release_exit;
+ /* turn off CSI regulator */
+ tegra_camera_power_off(dev);
+ if (ret)
+ goto release_exit;
+
+release_exit:
+ mutex_unlock(&dev->tegra_camera_lock);
+ WARN_ON(!atomic_xchg(&dev->in_use, 0));
return 0;
}
@@ -472,7 +413,6 @@ static int tegra_camera_probe(struct platform_device *pdev)
/* Powergate VE when boot */
mutex_lock(&dev->tegra_camera_lock);
- dev->power_refcnt = 0;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
err = tegra_powergate_partition(TEGRA_POWERGATE_VENC);
if (err)
@@ -574,12 +514,14 @@ static int tegra_camera_suspend(struct platform_device *pdev, pm_message_t state
struct tegra_camera_dev *dev = platform_get_drvdata(pdev);
int ret = 0;
- if (tegra_camera_enabled(dev)) {
+ mutex_lock(&dev->tegra_camera_lock);
+ if (dev->power_on) {
ret = -EBUSY;
dev_err(&pdev->dev,
"tegra_camera cannot suspend, "
"application is holding on to camera. \n");
}
+ mutex_unlock(&dev->tegra_camera_lock);
return ret;
}
diff --git a/drivers/mfd/max77663-core.c b/drivers/mfd/max77663-core.c
index ff47cb1..46728c3 100644
--- a/drivers/mfd/max77663-core.c
+++ b/drivers/mfd/max77663-core.c
@@ -118,6 +118,8 @@
#define ONOFF_SLP_LPM_MASK (1 << 5)
+#define ONOFF_IRQ_EN0_RISING (1 << 3)
+
enum {
CACHE_IRQ_LBT,
CACHE_IRQ_SD,
@@ -903,6 +905,8 @@ static void max77663_irq_sync_unlock(struct irq_data *data)
irq_mask = irq_data->trigger_type;
else
irq_mask = GPIO_REFE_IRQ_EDGE_FALLING << shift;
+ } else {
+ irq_mask = GPIO_REFE_IRQ_NONE << shift;
}
ret = max77663_cache_write(chip->dev, GPIO_REG_ADDR(offset),
@@ -1132,6 +1136,10 @@ static int max77663_irq_init(struct max77663_chip *chip)
max77663_write(chip->dev, MAX77663_REG_LBT_IRQ_MASK,
&chip->cache_irq_mask[CACHE_IRQ_LBT], 1, 0);
+ chip->cache_irq_mask[CACHE_IRQ_ONOFF] &= ~ONOFF_IRQ_EN0_RISING;
+ max77663_write(chip->dev, MAX77663_REG_ONOFF_IRQ_MASK,
+ &chip->cache_irq_mask[CACHE_IRQ_ONOFF], 1, 0);
+
return 0;
}
diff --git a/drivers/mfd/max8907c.c b/drivers/mfd/max8907c.c
index ba85a00..f8964cb 100644
--- a/drivers/mfd/max8907c.c
+++ b/drivers/mfd/max8907c.c
@@ -275,6 +275,7 @@ static int max8907c_i2c_probe(struct i2c_client *i2c,
struct max8907c_platform_data *pdata = i2c->dev.platform_data;
int ret;
int i;
+ u8 tmp;
max8907c = kzalloc(sizeof(struct max8907c), GFP_KERNEL);
if (max8907c == NULL)
@@ -298,7 +299,7 @@ static int max8907c_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(max8907c->dev, -1, cells, ARRAY_SIZE(cells),
NULL, 0);
if (ret != 0) {
- i2c_unregister_device(max8907c->i2c_rtc);
+ i2c_unregister_device(max8907c->i2c_rtc);
kfree(max8907c);
pr_debug("max8907c: failed to add MFD devices %X\n", ret);
return ret;
@@ -313,6 +314,18 @@ static int max8907c_i2c_probe(struct i2c_client *i2c,
if (pdata->use_power_off && !pm_power_off)
pm_power_off = max8907c_power_off;
+ ret = max8907c_i2c_read(i2c, MAX8907C_REG_SYSENSEL, 1, &tmp);
+ /*Mask HARD RESET, if enabled */
+ if (ret == 0) {
+ tmp &= ~(BIT(7));
+ ret = max8907c_i2c_write(i2c, MAX8907C_REG_SYSENSEL, 1, &tmp);
+ }
+
+ if (ret != 0) {
+ pr_err("Failed to write max8907c I2C driver: %d\n", ret);
+ return ret;
+ }
+
if (pdata->max8907c_setup)
return pdata->max8907c_setup();
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c
index e8ea75c..94ba777 100644
--- a/drivers/mfd/tps80031.c
+++ b/drivers/mfd/tps80031.c
@@ -874,8 +874,22 @@ static irqreturn_t tps80031_irq(int irq, void *data)
acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
if (acks) {
- ret = tps80031_writes(tps80031->dev, SLAVE_ID2,
- TPS80031_INT_STS_A, 3, tmp);
+ /*
+ * Hardware behavior: hardware have the shadow register for
+ * interrupt status register which is updated if interrupt
+ * comes just after the interrupt status read. This shadow
+ * register gets written to main status register and cleared
+ * if any byte write happens in any of status register like
+ * STS_A, STS_B or STS_C.
+ * Hence here to clear the original interrupt status and
+ * updating the STS register with the shadow register, it is
+ * require to write only one byte in any of STS register.
+ * Having multiple register write can cause the STS register
+ * to clear without handling those interrupt and can cause
+ * interrupt miss.
+ */
+ ret = tps80031_write(tps80031->dev, SLAVE_ID2,
+ TPS80031_INT_STS_A, 0);
if (ret < 0) {
dev_err(tps80031->dev, "failed to write "
"interrupt status\n");
diff --git a/drivers/misc/bcm4329_rfkill.c b/drivers/misc/bcm4329_rfkill.c
index a077326..cf56768 100644
--- a/drivers/misc/bcm4329_rfkill.c
+++ b/drivers/misc/bcm4329_rfkill.c
@@ -44,6 +44,13 @@ static struct bcm4329_rfkill_data *bcm4329_rfkill;
static int bcm4329_bt_rfkill_set_power(void *data, bool blocked)
{
+ /*
+ * check if BT gpio_shutdown line status and current request are same.
+ * If same, then return, else perform requested operation.
+ */
+ if (gpio_get_value(bcm4329_rfkill->gpio_shutdown) && !blocked)
+ return 0;
+
if (blocked) {
if (bcm4329_rfkill->gpio_shutdown)
gpio_direction_output(bcm4329_rfkill->gpio_shutdown, 0);
diff --git a/drivers/misc/nct1008.c b/drivers/misc/nct1008.c
index 8931c8a..d58757f 100644
--- a/drivers/misc/nct1008.c
+++ b/drivers/misc/nct1008.c
@@ -32,8 +32,6 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-#define DRIVER_NAME "nct1008"
-
/* Register Addresses */
#define LOCAL_TEMP_RD 0x00
#define EXT_TEMP_RD_HI 0x01
@@ -403,7 +401,7 @@ static void print_reg(const char *reg_name, struct seq_file *s,
static int dbg_nct1008_show(struct seq_file *s, void *unused)
{
- seq_printf(s, "nct1008 Registers\n");
+ seq_printf(s, "nct1008 nct72 Registers\n");
seq_printf(s, "------------------\n");
print_reg("Local Temp Value ", s, 0x00);
print_reg("Ext Temp Value Hi ", s, 0x01);
@@ -442,8 +440,12 @@ static int __init nct1008_debuginit(struct nct1008_data *nct)
{
int err = 0;
struct dentry *d;
- d = debugfs_create_file("nct1008", S_IRUGO, NULL,
- (void *)nct, &debug_fops);
+ if (nct->chip == NCT72)
+ d = debugfs_create_file("nct72", S_IRUGO, NULL,
+ (void *)nct, &debug_fops);
+ else
+ d = debugfs_create_file("nct1008", S_IRUGO, NULL,
+ (void *)nct, &debug_fops);
if ((!d) || IS_ERR(d)) {
dev_err(&nct->client->dev, "Error: %s debugfs_create_file"
" returned an error\n", __func__);
@@ -563,12 +565,14 @@ static void nct1008_power_control(struct nct1008_data *data, bool is_enable)
ret = regulator_disable(data->nct_reg);
if (ret < 0)
- dev_err(&data->client->dev, "Error in %s rail vdd_nct1008, "
+ dev_err(&data->client->dev, "Error in %s rail vdd_nct%s, "
"error %d\n", (is_enable) ? "enabling" : "disabling",
+ (data->chip == NCT72) ? "72" : "1008",
ret);
else
- dev_info(&data->client->dev, "success in %s rail vdd_nct1008\n",
- (is_enable) ? "enabling" : "disabling");
+ dev_info(&data->client->dev, "success in %s rail vdd_nct%s\n",
+ (is_enable) ? "enabling" : "disabling",
+ (data->chip == NCT72) ? "72" : "1008");
}
static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
@@ -692,7 +696,8 @@ error:
static int __devinit nct1008_configure_irq(struct nct1008_data *data)
{
- data->workqueue = create_singlethread_workqueue("nct1008");
+ data->workqueue = create_singlethread_workqueue((data->chip == NCT72) \
+ ? "nct72" : "nct1008");
INIT_WORK(&data->work, nct1008_work_func);
@@ -701,7 +706,8 @@ static int __devinit nct1008_configure_irq(struct nct1008_data *data)
else
return request_irq(data->client->irq, nct1008_irq,
IRQF_TRIGGER_LOW,
- DRIVER_NAME, data);
+ (data->chip == NCT72) ? "nct72" : "nct1008",
+ data);
}
int nct1008_thermal_get_temp(struct nct1008_data *data, long *temp)
@@ -810,13 +816,13 @@ static int __devinit nct1008_probe(struct i2c_client *client,
{
struct nct1008_data *data;
int err;
- unsigned int delay;
data = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
+ data->chip = id->driver_data;
memcpy(&data->plat_data, client->dev.platform_data,
sizeof(struct nct1008_platform_data));
i2c_set_clientdata(client, data);
@@ -897,7 +903,6 @@ static int nct1008_suspend(struct i2c_client *client, pm_message_t state)
static int nct1008_resume(struct i2c_client *client)
{
- struct nct1008_data *data = i2c_get_clientdata(client);
int err;
err = nct1008_enable(client);
@@ -913,14 +918,15 @@ static int nct1008_resume(struct i2c_client *client)
#endif
static const struct i2c_device_id nct1008_id[] = {
- { DRIVER_NAME, 0 },
- { }
+ { "nct1008", NCT1008 },
+ { "nct72", NCT72},
+ {}
};
MODULE_DEVICE_TABLE(i2c, nct1008_id);
static struct i2c_driver nct1008_driver = {
.driver = {
- .name = DRIVER_NAME,
+ .name = "nct1008_nct72",
},
.probe = nct1008_probe,
.remove = __devexit_p(nct1008_remove),
@@ -941,7 +947,7 @@ static void __exit nct1008_exit(void)
i2c_del_driver(&nct1008_driver);
}
-MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008");
+MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008/NCT72");
MODULE_LICENSE("GPL");
module_init(nct1008_init);
diff --git a/drivers/misc/tegra-cryptodev.c b/drivers/misc/tegra-cryptodev.c
index d5ed6a22d..d767ea0 100644
--- a/drivers/misc/tegra-cryptodev.c
+++ b/drivers/misc/tegra-cryptodev.c
@@ -31,14 +31,20 @@
#include <linux/scatterlist.h>
#include <linux/uaccess.h>
#include <crypto/rng.h>
+#include <crypto/hash.h>
+#include <mach/hardware.h>
#include "tegra-cryptodev.h"
#define NBUFS 2
+#define XBUFSIZE 8
struct tegra_crypto_ctx {
struct crypto_ablkcipher *ecb_tfm;
struct crypto_ablkcipher *cbc_tfm;
+ struct crypto_ablkcipher *ofb_tfm;
+ struct crypto_ablkcipher *ctr_tfm;
+ struct crypto_ablkcipher *cmac_tfm;
struct crypto_rng *rng;
u8 seed[TEGRA_CRYPTO_RNG_SEED_SIZE];
int use_ssk;
@@ -105,6 +111,26 @@ static int tegra_crypto_dev_open(struct inode *inode, struct file *filp)
goto fail_cbc;
}
+ if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2) {
+ ctx->ofb_tfm = crypto_alloc_ablkcipher("ofb-aes-tegra",
+ CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 0);
+ if (IS_ERR(ctx->ofb_tfm)) {
+ pr_err("Failed to load transform for ofb-aes-tegra: %ld\n",
+ PTR_ERR(ctx->ofb_tfm));
+ ret = PTR_ERR(ctx->ofb_tfm);
+ goto fail_ofb;
+ }
+
+ ctx->ctr_tfm = crypto_alloc_ablkcipher("ctr-aes-tegra",
+ CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 0);
+ if (IS_ERR(ctx->ctr_tfm)) {
+ pr_err("Failed to load transform for ctr-aes-tegra: %ld\n",
+ PTR_ERR(ctx->ctr_tfm));
+ ret = PTR_ERR(ctx->ctr_tfm);
+ goto fail_ctr;
+ }
+ }
+
ctx->rng = crypto_alloc_rng("rng-aes-tegra", CRYPTO_ALG_TYPE_RNG, 0);
if (IS_ERR(ctx->rng)) {
pr_err("Failed to load transform for tegra rng: %ld\n",
@@ -117,6 +143,12 @@ static int tegra_crypto_dev_open(struct inode *inode, struct file *filp)
return ret;
fail_rng:
+ if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)
+ crypto_free_ablkcipher(ctx->ctr_tfm);
+fail_ctr:
+ if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)
+ crypto_free_ablkcipher(ctx->ofb_tfm);
+fail_ofb:
crypto_free_ablkcipher(ctx->cbc_tfm);
fail_cbc:
@@ -133,6 +165,12 @@ static int tegra_crypto_dev_release(struct inode *inode, struct file *filp)
crypto_free_ablkcipher(ctx->ecb_tfm);
crypto_free_ablkcipher(ctx->cbc_tfm);
+
+ if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2) {
+ crypto_free_ablkcipher(ctx->ofb_tfm);
+ crypto_free_ablkcipher(ctx->ctr_tfm);
+ }
+
crypto_free_rng(ctx->rng);
kfree(ctx);
filp->private_data = NULL;
@@ -158,16 +196,27 @@ static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_re
unsigned long *xbuf[NBUFS];
int ret = 0, size = 0;
unsigned long total = 0;
- struct tegra_crypto_completion tcrypt_complete;
const u8 *key = NULL;
+ struct tegra_crypto_completion tcrypt_complete;
if (crypt_req->op & TEGRA_CRYPTO_ECB) {
req = ablkcipher_request_alloc(ctx->ecb_tfm, GFP_KERNEL);
tfm = ctx->ecb_tfm;
- } else {
+ } else if (crypt_req->op & TEGRA_CRYPTO_CBC) {
req = ablkcipher_request_alloc(ctx->cbc_tfm, GFP_KERNEL);
tfm = ctx->cbc_tfm;
+ } else if ((crypt_req->op & TEGRA_CRYPTO_OFB) &&
+ (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)) {
+
+ req = ablkcipher_request_alloc(ctx->ofb_tfm, GFP_KERNEL);
+ tfm = ctx->ofb_tfm;
+ } else if ((crypt_req->op & TEGRA_CRYPTO_CTR) &&
+ (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)) {
+
+ req = ablkcipher_request_alloc(ctx->ctr_tfm, GFP_KERNEL);
+ tfm = ctx->ctr_tfm;
}
+
if (!req) {
pr_err("%s: Failed to allocate request\n", __func__);
return -ENOMEM;
@@ -254,12 +303,121 @@ process_req_out:
return ret;
}
+static int sha_async_hash_op(struct ahash_request *req,
+ struct tegra_crypto_completion *tr,
+ int ret)
+{
+ if (ret == -EINPROGRESS || ret == -EBUSY) {
+ ret = wait_for_completion_interruptible(&tr->restart);
+ if (!ret)
+ ret = tr->req_err;
+ INIT_COMPLETION(tr->restart);
+ }
+ return ret;
+}
+
+static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
+{
+
+ struct crypto_ahash *tfm;
+ struct scatterlist sg[1];
+ char result[64];
+ struct ahash_request *req;
+ struct tegra_crypto_completion sha_complete;
+ void *hash_buff;
+ unsigned long *xbuf[XBUFSIZE];
+ int ret = -ENOMEM;
+
+ tfm = crypto_alloc_ahash(sha_req->algo, 0, 0);
+ if (IS_ERR(tfm)) {
+ printk(KERN_ERR "alg: hash: Failed to load transform for %s: "
+ "%ld\n", sha_req->algo, PTR_ERR(tfm));
+ goto out_alloc;
+ }
+
+ req = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ printk(KERN_ERR "alg: hash: Failed to allocate request for "
+ "%s\n", sha_req->algo);
+ goto out_noreq;
+ }
+
+ ret = alloc_bufs(xbuf);
+ if (ret < 0) {
+ pr_err("alloc_bufs failed");
+ goto out_buf;
+ }
+
+ init_completion(&sha_complete.restart);
+
+ memset(result, 0, 64);
+
+ hash_buff = xbuf[0];
+
+ memcpy(hash_buff, sha_req->plaintext, sha_req->plaintext_sz);
+ sg_init_one(&sg[0], hash_buff, sha_req->plaintext_sz);
+
+ if (sha_req->keylen) {
+ crypto_ahash_clear_flags(tfm, ~0);
+ ret = crypto_ahash_setkey(tfm, sha_req->key,
+ sha_req->keylen);
+ if (ret) {
+ printk(KERN_ERR "alg: hash: setkey failed on "
+ " %s: ret=%d\n", sha_req->algo,
+ -ret);
+ goto out;
+ }
+ }
+
+ ahash_request_set_crypt(req, sg, result, sha_req->plaintext_sz);
+
+ ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_init(req));
+ if (ret) {
+ pr_err("alg: hash: init failed on "
+ "for %s: ret=%d\n", sha_req->algo, -ret);
+ goto out;
+ }
+
+ ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_update(req));
+ if (ret) {
+ pr_err("alg: hash: update failed on "
+ "for %s: ret=%d\n", sha_req->algo, -ret);
+ goto out;
+ }
+
+ ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_final(req));
+ if (ret) {
+ pr_err("alg: hash: final failed on "
+ "for %s: ret=%d\n", sha_req->algo, -ret);
+ goto out;
+ }
+
+ ret = copy_to_user((void __user *)sha_req->result,
+ (const void *)result, crypto_ahash_digestsize(tfm));
+ if (ret < 0)
+ goto out;
+
+out:
+ free_bufs(xbuf);
+
+out_buf:
+ ahash_request_free(req);
+
+out_noreq:
+ crypto_free_ahash(tfm);
+
+out_alloc:
+ return ret;
+
+}
+
static long tegra_crypto_dev_ioctl(struct file *filp,
unsigned int ioctl_num, unsigned long arg)
{
struct tegra_crypto_ctx *ctx = filp->private_data;
struct tegra_crypt_req crypt_req;
struct tegra_rng_req rng_req;
+ struct tegra_sha_req sha_req;
char *rng;
int ret = 0;
@@ -316,6 +474,17 @@ rng_out:
kfree(rng);
break;
+ case TEGRA_CRYPTO_IOCTL_GET_SHA:
+ if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2) {
+ if (copy_from_user(&sha_req, (void __user *)arg,
+ sizeof(sha_req)))
+ return -EFAULT;
+ ret = tegra_crypto_sha(&sha_req);
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+
default:
pr_debug("invalid ioctl code(%d)", ioctl_num);
ret = -EINVAL;
diff --git a/drivers/misc/tegra-cryptodev.h b/drivers/misc/tegra-cryptodev.h
index ed62a52..34ec9c1 100644
--- a/drivers/misc/tegra-cryptodev.h
+++ b/drivers/misc/tegra-cryptodev.h
@@ -28,6 +28,7 @@
#define TEGRA_CRYPTO_IOCTL_PROCESS_REQ _IOWR(0x98, 101, int*)
#define TEGRA_CRYPTO_IOCTL_SET_SEED _IOWR(0x98, 102, int*)
#define TEGRA_CRYPTO_IOCTL_GET_RANDOM _IOWR(0x98, 103, int*)
+#define TEGRA_CRYPTO_IOCTL_GET_SHA _IOWR(0x98, 104, int*)
#define TEGRA_CRYPTO_MAX_KEY_SIZE AES_MAX_KEY_SIZE
#define TEGRA_CRYPTO_IV_SIZE AES_BLOCK_SIZE
@@ -40,7 +41,10 @@
/* encrypt/decrypt operations */
#define TEGRA_CRYPTO_ECB BIT(0)
#define TEGRA_CRYPTO_CBC BIT(1)
-#define TEGRA_CRYPTO_RNG BIT(2)
+#define TEGRA_CRYPTO_OFB BIT(2)
+#define TEGRA_CRYPTO_CTR BIT(3)
+#define TEGRA_CRYPTO_CMAC BIT(4)
+#define TEGRA_CRYPTO_RNG BIT(5)
/* a pointer to this struct needs to be passed to:
* TEGRA_CRYPTO_IOCTL_PROCESS_REQ
@@ -67,4 +71,13 @@ struct tegra_rng_req {
int nbytes; /* random data length */
};
+struct tegra_sha_req {
+ char key[TEGRA_CRYPTO_MAX_KEY_SIZE];
+ int keylen;
+ unsigned char *algo;
+ unsigned char *plaintext;
+ int plaintext_sz;
+ unsigned char *result;
+};
+
#endif
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index ebb4afe..3875c21e 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -76,3 +76,13 @@ config MMC_TEST
This driver is only of interest to those developing or
testing a host driver. Most people should say N here.
+
+config MMC_BKOPS
+ bool "Enable background ops"
+ default n
+ help
+ Say Y here to enable background ops in driver. This will result
+ in issuing of MMC_SWITCH command to write byte 164 of EXT_CSD,
+ in order to trigger background ops in the MMC device's
+ firmware, whenever URGENT_BKOPS flag is found to be set in a
+ read/write command's response.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 2bd93d7a5..bd5427d 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -59,8 +59,6 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
-#define MMC_CMD_RETRIES 10
-
static DEFINE_MUTEX(block_mutex);
/*
@@ -945,7 +943,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
if (!mmc_card_blockaddr(card))
brq->cmd.arg <<= 9;
brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq->cmd.retries = MMC_CMD_RETRIES;
brq->data.blksz = 512;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 440b97d..8681708 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -211,7 +211,7 @@ static struct mmc_test_parameter mmc_test_parameter[] = {
static long mmc_test_set_testcase(struct mmc_test_card *test)
{
- return 0;
+ return mmc_test_parameter[0].value;
}
static long mmc_test_set_clock(struct mmc_test_card *test)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2a288e9..c5338cd 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -109,11 +109,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
cmd->retries--;
cmd->error = 0;
- if (mrq->data) {
- mrq->data->error = 0;
- if (mrq->stop)
- mrq->stop->error = 0;
- }
host->ops->request(host, mrq);
} else {
led_trigger_event(host->led, LED_OFF);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 330b968..28bed97 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -588,7 +588,7 @@ int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous)
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_BKOPS_EN << 16) |
+ (EXT_CSD_BKOPS_START << 16) |
(1 << 8) |
EXT_CSD_CMD_SET_NORMAL;
if (is_synchronous)
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 4dfe817..8fec147 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -70,11 +70,14 @@
static unsigned int tegra_sdhost_min_freq;
static unsigned int tegra_sdhost_std_freq;
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock);
static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci);
static unsigned int tegra3_sdhost_max_clk[4] = {
208000000, 104000000, 208000000, 104000000 };
+#endif
struct tegra_sdhci_hw_ops{
/* Set the internal clk and card clk.*/
@@ -109,9 +112,13 @@ struct tegra_sdhci_host {
unsigned int vddio_max_uv;
/* max clk supported by the platform */
unsigned int max_clk_limit;
+ /* max ddr clk supported by the platform */
+ unsigned int ddr_clk_limit;
struct tegra_io_dpd *dpd;
bool card_present;
bool is_rail_enabled;
+ struct clk *emc_clk;
+ unsigned int emc_max_clk;
};
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
@@ -183,6 +190,7 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
return gpio_get_value(plat->wp_gpio);
}
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci)
{
u16 misc_ctrl;
@@ -219,6 +227,7 @@ static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci)
SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR50_SUPPORT;
sdhci_writew(sdhci, misc_ctrl, SDHCI_VENDOR_MISC_CNTRL);
}
+#endif
static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
unsigned int uhs)
@@ -361,14 +370,30 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
struct tegra_sdhci_host *tegra_host = pltfm_host->priv;
unsigned int clk_rate;
+ unsigned int emc_clk;
+ /*
+ * In SDR50 mode, run the sdmmc controller at freq greater than
+ * 104MHz to ensure the core voltage is at 1.2V. If the core voltage
+ * is below 1.2V, CRC errors would occur during data transfers.
+ */
if (sdhci->mmc->card &&
- mmc_card_ddr_mode(sdhci->mmc->card)) {
+ (mmc_card_ddr_mode(sdhci->mmc->card) ||
+ (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50))) {
/*
* In ddr mode, tegra sdmmc controller clock frequency
* should be double the card clock frequency.
*/
- clk_rate = clock * 2;
+ if (tegra_host->ddr_clk_limit) {
+ clk_rate = tegra_host->ddr_clk_limit * 2;
+ if (tegra_host->emc_clk) {
+ emc_clk = clk_get_rate(tegra_host->emc_clk);
+ if (emc_clk == tegra_host->emc_max_clk)
+ clk_rate = clock * 2;
+ }
+ } else {
+ clk_rate = clock * 2;
+ }
} else {
if (clock <= tegra_sdhost_min_freq)
clk_rate = tegra_sdhost_min_freq;
@@ -376,15 +401,6 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
clk_rate = tegra_sdhost_std_freq;
else
clk_rate = clock;
-
- /*
- * In SDR50 mode, run the sdmmc controller at 208MHz to ensure
- * the core voltage is at 1.2V. If the core voltage is below 1.2V, CRC
- * errors would occur during data transfers.
- */
- if ((sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) &&
- (clk_rate == tegra_sdhost_std_freq))
- clk_rate <<= 1;
}
if (tegra_host->max_clk_limit &&
@@ -395,6 +411,7 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
sdhci->max_clk = clk_get_rate(pltfm_host->clk);
}
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock)
{
int div;
@@ -405,6 +422,13 @@ static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int
if (clock && clock == sdhci->clock)
return;
+ /*
+ * Disable the card clock before disabling the internal
+ * clock to avoid abnormal clock waveforms.
+ */
+ clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL);
sdhci_writew(sdhci, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
@@ -472,6 +496,7 @@ set_clk:
out:
sdhci->clock = clock;
}
+#endif
static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
{
@@ -874,6 +899,9 @@ static struct sdhci_ops tegra_sdhci_ops = {
.read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel,
.platform_8bit_width = tegra_sdhci_8bit,
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ .set_card_clock = tegra_3x_sdhci_set_card_clock,
+#endif
.set_clock = tegra_sdhci_set_clock,
.suspend = tegra_sdhci_suspend,
.resume = tegra_sdhci_resume,
@@ -1018,8 +1046,9 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
}
tegra_host->vdd_io_reg = regulator_get(mmc_dev(host->mmc), "vddio_sdmmc");
if (IS_ERR_OR_NULL(tegra_host->vdd_io_reg)) {
- dev_err(mmc_dev(host->mmc), "%s regulator not found: %ld\n",
- "vddio_sdmmc", PTR_ERR(tegra_host->vdd_io_reg));
+ dev_info(mmc_dev(host->mmc), "%s regulator not found: %ld."
+ "Assuming vddio_sdmmc is not required.\n",
+ "vddio_sdmmc", PTR_ERR(tegra_host->vdd_io_reg));
tegra_host->vdd_io_reg = NULL;
} else {
rc = regulator_set_voltage(tegra_host->vdd_io_reg,
@@ -1033,8 +1062,9 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
tegra_host->vdd_slot_reg = regulator_get(mmc_dev(host->mmc), "vddio_sd_slot");
if (IS_ERR_OR_NULL(tegra_host->vdd_slot_reg)) {
- dev_err(mmc_dev(host->mmc), "%s regulator not found: %ld\n",
- "vddio_sd_slot", PTR_ERR(tegra_host->vdd_slot_reg));
+ dev_info(mmc_dev(host->mmc), "%s regulator not found: %ld."
+ " Assuming vddio_sd_slot is not required.\n",
+ "vddio_sd_slot", PTR_ERR(tegra_host->vdd_slot_reg));
tegra_host->vdd_slot_reg = NULL;
}
@@ -1056,10 +1086,23 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
rc = clk_enable(clk);
if (rc != 0)
goto err_clk_put;
+
+ if (!strcmp(dev_name(mmc_dev(host->mmc)), "sdhci-tegra.3")) {
+ tegra_host->emc_clk = clk_get(mmc_dev(host->mmc), "emc");
+ if (IS_ERR(tegra_host->emc_clk)) {
+ dev_err(mmc_dev(host->mmc), "clk err\n");
+ rc = PTR_ERR(tegra_host->emc_clk);
+ goto err_clk_put;
+ }
+ tegra_host->emc_max_clk =
+ clk_round_rate(tegra_host->emc_clk, ULONG_MAX);
+ }
+
pltfm_host->clk = clk;
pltfm_host->priv = tegra_host;
tegra_host->clk_enabled = true;
tegra_host->max_clk_limit = plat->max_clk_limit;
+ tegra_host->ddr_clk_limit = plat->ddr_clk_limit;
tegra_host->instance = pdev->id;
tegra_host->dpd = tegra_io_dpd_get(mmc_dev(host->mmc));
@@ -1077,11 +1120,18 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY;
if (plat->mmc_data.built_in) {
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
- host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
}
+ host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
+
+#ifdef CONFIG_MMC_BKOPS
+ host->mmc->caps |= MMC_CAP_BKOPS;
+#endif
+
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
/* Do not turn OFF embedded sdio cards as it support Wake on Wireless */
if (plat->mmc_data.embedded_sdio)
host->mmc->pm_flags |= MMC_PM_KEEP_POWER;
+#endif
tegra_sdhost_min_freq = TEGRA_SDHOST_MIN_FREQ;
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -1099,6 +1149,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
return 0;
err_add_host:
+ clk_put(tegra_host->emc_clk);
clk_disable(pltfm_host->clk);
err_clk_put:
clk_put(pltfm_host->clk);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c6822c3..4955869 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1352,7 +1352,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->version >= SDHCI_SPEC_300) {
u16 clk, ctrl_2;
- unsigned int clock;
/* In case of UHS-I modes, set High Speed Enable */
if (((ios->timing == MMC_TIMING_UHS_SDR50) ||
@@ -1851,13 +1850,18 @@ int sdhci_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
- if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
+ if (!mmc->card)
return 0;
if (mmc->ios.clock) {
- if (host->ops->set_clock)
- host->ops->set_clock(host, mmc->ios.clock);
- sdhci_set_clock(host, mmc->ios.clock);
+ if (mmc->card->type != MMC_TYPE_SDIO) {
+ if (host->ops->set_clock)
+ host->ops->set_clock(host, mmc->ios.clock);
+ sdhci_set_clock(host, mmc->ios.clock);
+ } else {
+ if (host->ops->set_card_clock)
+ host->ops->set_card_clock(host, mmc->ios.clock);
+ }
}
return 0;
@@ -1867,12 +1871,18 @@ int sdhci_disable(struct mmc_host *mmc, int lazy)
{
struct sdhci_host *host = mmc_priv(mmc);
- if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
+ if (!mmc->card)
return 0;
- sdhci_set_clock(host, 0);
- if (host->ops->set_clock)
- host->ops->set_clock(host, 0);
+ /* For SDIO cards, only disable the card clock. */
+ if (mmc->card->type != MMC_TYPE_SDIO) {
+ sdhci_set_clock(host, 0);
+ if (host->ops->set_clock)
+ host->ops->set_clock(host, 0);
+ } else {
+ if (host->ops->set_card_clock)
+ host->ops->set_card_clock(host, 0);
+ }
return 0;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c00833d..bf48767 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -260,6 +260,7 @@ struct sdhci_ops {
#endif
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
+ void (*set_card_clock)(struct sdhci_host *host, unsigned int clock);
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 34f83a4..dc44c5c 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -277,13 +277,8 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
DMA_TO_DEVICE);
if (ret > 0) {
host->dma_active = true;
-<<<<<<< HEAD
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
- DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-=======
desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
}
if (desc) {
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index d298e7b..def9c54 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -157,13 +157,8 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0)
-<<<<<<< HEAD
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
- DMA_TO_DEVICE, DMA_CTRL_ACK);
-=======
desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_MEM_TO_DEV, DMA_CTRL_ACK);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (desc) {
cookie = dmaengine_submit(desc);
diff --git a/drivers/mtd/maps/tegra_nor.c b/drivers/mtd/maps/tegra_nor.c
index b455fd5..cc80a0b 100644
--- a/drivers/mtd/maps/tegra_nor.c
+++ b/drivers/mtd/maps/tegra_nor.c
@@ -279,7 +279,7 @@ static int tegra_snor_controller_init(struct tegra_nor_info *info)
info->timing0_default = chip_parm->timing_default.timing0;
info->timing0_read = chip_parm->timing_read.timing0;
info->timing1_default = chip_parm->timing_default.timing1;
- info->timing1_read = chip_parm->timing_read.timing0;
+ info->timing1_read = chip_parm->timing_read.timing1;
snor_tegra_writel(info, info->timing1_default, TEGRA_SNOR_TIMING1_REG);
snor_tegra_writel(info, info->timing0_default, TEGRA_SNOR_TIMING0_REG);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 4fba62a..aa826d9 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -574,12 +574,17 @@ static const struct usb_device_id products [] = {
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
- USB_DEVICE(0x1983,0x0310),
+ USB_DEVICE(0x1983, 0x0310),
.driver_info = (unsigned long)&wwan_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
- USB_DEVICE(0x1983,0x0321),
+ USB_DEVICE(0x1983, 0x0321),
+ .driver_info = (unsigned long)&wwan_info,
+}, {
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+ | USB_DEVICE_ID_MATCH_DEVICE,
+ USB_DEVICE(0x1983, 0x0327), /* 5AE */
.driver_info = (unsigned long)&wwan_info,
},
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index fc5f13d..47eac7b 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -222,13 +222,8 @@ static const struct driver_info blob_info = {
#endif /* CONFIG_USB_ARMLINUX */
-
/*-------------------------------------------------------------------------*/
-#ifndef HAVE_HARDWARE
-#warning You need to configure some hardware for this driver
-#endif
-
/*
* chip vendor names won't normally be on the cables, and
* may not be on the device.
diff --git a/drivers/net/usb/raw_ip_net.c b/drivers/net/usb/raw_ip_net.c
index 35b6969..1b3b89b 100644
--- a/drivers/net/usb/raw_ip_net.c
+++ b/drivers/net/usb/raw_ip_net.c
@@ -67,8 +67,13 @@ module_param(usb_net_raw_ip_tx_debug, ulong, 0644);
MODULE_PARM_DESC(usb_net_raw_ip_tx_debug, "usb net (raw-ip) - tx debug");
struct baseband_usb {
+ /* semaphore between disconnect/suspend/resume */
+ struct semaphore sem;
+ /* instance */
int baseband_index;
+ /* network statistics */
struct net_device_stats stats;
+ /* usb context */
struct {
struct usb_driver *driver;
struct usb_device *device;
@@ -87,8 +92,11 @@ struct baseband_usb {
struct workqueue_struct *tx_workqueue;
struct work_struct tx_work;
} usb;
+ /* re-usable rx urb */
struct urb *urb_r;
void *buff;
+ /* suspend count */
+ int susp_count;
};
static struct baseband_usb *baseband_usb_net[MAX_INTFS] = { 0, 0, 0};
@@ -158,6 +166,11 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
baseband_usb_net[i]->usb.interface, intf);
continue;
}
+ /* acquire semaphore */
+ if (down_interruptible(&baseband_usb_net[i]->sem)) {
+ pr_err("%s: cannot acquire semaphore\n", __func__);
+ continue;
+ }
/* kill usb tx */
while ((urb = usb_get_from_anchor(&baseband_usb_net[i]->
usb.tx_urb_deferred)) != (struct urb *) 0) {
@@ -192,6 +205,8 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
/* mark interface as disconnected */
baseband_usb_net[i]->usb.interface
= (struct usb_interface *) 0;
+ /* release semaphore */
+ up(&baseband_usb_net[i]->sem);
}
}
@@ -200,10 +215,14 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
static int baseband_usb_driver_suspend(struct usb_interface *intf,
pm_message_t message)
{
- int i;
+ int i, susp_count;
pr_debug("%s intf %p\n", __func__, intf);
+ pr_debug("%s: cnt %d intf=%p &intf->dev=%p kobj=%s\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ intf, &intf->dev, kobject_name(&intf->dev.kobj));
+
for (i = 0; i < max_intfs; i++) {
pr_debug("[%d]\n", i);
if (!baseband_usb_net[i])
@@ -213,13 +232,47 @@ static int baseband_usb_driver_suspend(struct usb_interface *intf,
baseband_usb_net[i]->usb.interface, intf);
continue;
}
+ /* increment suspend count */
+ susp_count = (baseband_usb_net[i]->susp_count)++;
+ if (susp_count > 0) {
+ pr_debug("%s: susp_count %d > 0 (already suspended)\n",
+ __func__, susp_count);
+ continue;
+ }
+ if (susp_count < 0) {
+ pr_debug("%s: susp_count %d < 0 (ILLEGAL VALUE)\n",
+ __func__, susp_count);
+ baseband_usb_net[i]->susp_count = 0;
+ continue;
+ }
+ pr_debug("%s: susp_count = %d (suspending...)\n",
+ __func__, susp_count);
+ /* acquire semaphore */
+ if (down_interruptible(&baseband_usb_net[i]->sem)) {
+ pr_err("%s: cannot acquire semaphore\n", __func__);
+ continue;
+ }
/* kill usb rx */
if (!baseband_usb_net[i]->usb.rx_urb) {
pr_debug("rx_usb already killed\n");
+ up(&baseband_usb_net[i]->sem);
continue;
}
+ pr_debug("%s: kill rx_urb {\n",__func__);
usb_kill_urb(baseband_usb_net[i]->usb.rx_urb);
+ pr_debug("%s: kill rx_urb }\n",__func__);
baseband_usb_net[i]->usb.rx_urb = (struct urb *) 0;
+ /* cancel tx urb work (will restart after resume) */
+ if (!baseband_usb_net[i]->usb.tx_workqueue) {
+ pr_err("%s: !tx_workqueue\n", __func__);
+ up(&baseband_usb_net[i]->sem);
+ continue;
+ }
+ pr_debug("%s: cancel_work_sync {\n",__func__);
+ cancel_work_sync(&baseband_usb_net[i]->usb.tx_work);
+ pr_debug("%s: cancel_work_sync }\n",__func__);
+ /* release semaphore */
+ up(&baseband_usb_net[i]->sem);
}
return 0;
@@ -227,10 +280,14 @@ static int baseband_usb_driver_suspend(struct usb_interface *intf,
static int baseband_usb_driver_resume(struct usb_interface *intf)
{
- int i, err;
+ int i, err, susp_count;
pr_debug("%s intf %p\n", __func__, intf);
+ pr_debug("%s: cnt %d intf=%p &intf->dev=%p kobj=%s\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ intf, &intf->dev, kobject_name(&intf->dev.kobj));
+
for (i = 0; i < max_intfs; i++) {
pr_debug("[%d]\n", i);
if (!baseband_usb_net[i])
@@ -240,16 +297,48 @@ static int baseband_usb_driver_resume(struct usb_interface *intf)
baseband_usb_net[i]->usb.interface, intf);
continue;
}
+ /* decrement suspend count */
+ susp_count = --(baseband_usb_net[i]->susp_count);
+ if (susp_count > 0) {
+ pr_debug("%s: susp_count %d > 0 (not resuming yet)\n",
+ __func__, susp_count);
+ continue;
+ }
+ if (susp_count < 0) {
+ pr_debug("%s: susp_count %d < 0 (ILLEGAL VALUE)\n",
+ __func__, susp_count);
+ baseband_usb_net[i]->susp_count = 0;
+ continue;
+ }
+ pr_debug("%s: susp_count = %d (resuming...)\n",
+ __func__, susp_count);
+ /* acquire semaphore */
+ if (down_interruptible(&baseband_usb_net[i]->sem)) {
+ pr_err("%s: cannot acquire semaphore\n", __func__);
+ continue;
+ }
/* start usb rx */
if (baseband_usb_net[i]->usb.rx_urb) {
pr_debug("rx_usb already exists\n");
+ up(&baseband_usb_net[i]->sem);
continue;
}
err = usb_net_raw_ip_rx_urb_submit(baseband_usb_net[i]);
if (err < 0) {
pr_err("submit rx failed - err %d\n", err);
+ up(&baseband_usb_net[i]->sem);
+ continue;
+ }
+ /* restart tx urb work (cancelled in suspend) */
+ if (!baseband_usb_net[i]->usb.tx_workqueue) {
+ pr_err("%s: !tx_workqueue\n", __func__);
+ up(&baseband_usb_net[i]->sem);
continue;
}
+ queue_work(baseband_usb_net[i]->usb.tx_workqueue,
+ &baseband_usb_net[i]->usb.tx_work);
+ /* release semaphore */
+ up(&baseband_usb_net[i]->sem);
}
return 0;
@@ -361,6 +450,9 @@ struct baseband_usb *baseband_usb_open(int index,
if (!usb)
return (struct baseband_usb *) 0;
+ /* create semaphores */
+ sema_init(&usb->sem, 1);
+
/* open usb driver */
sprintf(baseband_usb_driver_name[index],
"baseband_usb_%x_%x_%x",
@@ -424,6 +516,9 @@ void baseband_usb_close(struct baseband_usb *usb)
pr_debug("close usb driver }\n");
}
+ /* destroy semaphores */
+ memset(&usb->sem, 0, sizeof(usb->sem));
+
/* free baseband usb structure */
kfree(usb);
@@ -485,10 +580,21 @@ static netdev_tx_t baseband_usb_netdev_start_xmit(
}
usb = baseband_usb_net[i];
+ /* autoresume if suspended */
+ if (usb->usb.interface) {
+ usb_autopm_get_interface_async(usb->usb.interface);
+ } else {
+ pr_err("%s: tx get interface error\n", __func__);
+ netif_stop_queue(dev);
+ usb->stats.tx_errors++;
+ return NETDEV_TX_BUSY;
+ }
+
/* submit tx urb */
err = usb_net_raw_ip_tx_urb_submit(usb, skb);
if (err < 0) {
- pr_err("tx urb submit error\n");
+ pr_err("%s: tx urb submit error\n", __func__);
+ netif_stop_queue(dev);
usb->stats.tx_errors++;
return NETDEV_TX_BUSY;
}
@@ -570,8 +676,8 @@ static int usb_net_raw_ip_rx_urb_submit(struct baseband_usb *usb)
static void usb_net_raw_ip_rx_urb_comp(struct urb *urb)
{
- struct baseband_usb *usb = (struct baseband_usb *) urb->context;
- int i = usb->baseband_index;
+ struct baseband_usb *usb;
+ int i;
struct sk_buff *skb;
unsigned char *dst;
unsigned char ethernet_header[14] = {
@@ -594,17 +700,20 @@ static void usb_net_raw_ip_rx_urb_comp(struct urb *urb)
pr_err("no urb\n");
return;
}
+ usb = (struct baseband_usb *)urb->context;
+ i = usb->baseband_index;
switch (urb->status) {
case 0:
break;
- case -ENOENT:
- /* fall through */
case -ESHUTDOWN:
/* fall through */
- case -EPROTO:
pr_info("%s: rx urb %p - link shutdown %d\n",
__func__, urb, urb->status);
goto err_exit;
+ case -EPROTO:
+ pr_info("%s: rx urb %p - link shutdown %d EPROTO\n",
+ __func__, urb, urb->status);
+ goto err_exit;
default:
pr_info("%s: rx urb %p - status %d\n",
__func__, urb, urb->status);
@@ -612,7 +721,7 @@ static void usb_net_raw_ip_rx_urb_comp(struct urb *urb)
}
/* put rx urb data in rx buffer */
- if (urb->actual_length) {
+ if (urb->actual_length > 0) {
pr_debug("usb_net_raw_ip_rx_urb_comp - "
"urb->actual_length %d\n", urb->actual_length);
/* allocate skb with space for
@@ -661,6 +770,10 @@ static void usb_net_raw_ip_rx_urb_comp(struct urb *urb)
/* mark rx urb complete */
usb->usb.rx_urb = (struct urb *) 0;
+ /* do not submit urb if interface is suspending */
+ if (urb->status == -ENOENT)
+ return;
+
/* submit next rx urb */
usb_net_raw_ip_rx_urb_submit(usb);
return;
@@ -742,13 +855,13 @@ static int usb_net_raw_ip_tx_urb_submit(struct baseband_usb *usb,
pr_err("%s: !usb\n", __func__);
return -EINVAL;
}
- if (!skb) {
- pr_err("%s: !skb\n", __func__);
- return -EINVAL;
- }
if (!usb->usb.interface) {
pr_err("usb interface disconnected - not submitting tx urb\n");
- kfree_skb(skb);
+ return -EINVAL;
+ }
+ if (!skb) {
+ pr_err("%s: !skb\n", __func__);
+ usb_autopm_put_interface_async(usb->usb.interface);
return -EINVAL;
}
@@ -756,14 +869,14 @@ static int usb_net_raw_ip_tx_urb_submit(struct baseband_usb *usb,
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
pr_err("usb_alloc_urb() failed\n");
- kfree_skb(skb);
+ usb_autopm_put_interface_async(usb->usb.interface);
return -ENOMEM;
}
buf = kzalloc(skb->len - 14, GFP_ATOMIC);
if (!buf) {
pr_err("usb buffer kzalloc() failed\n");
usb_free_urb(urb);
- kfree_skb(skb);
+ usb_autopm_put_interface_async(usb->usb.interface);
return -ENOMEM;
}
err = skb_copy_bits(skb, 14, buf, skb->len - 14);
@@ -771,7 +884,7 @@ static int usb_net_raw_ip_tx_urb_submit(struct baseband_usb *usb,
pr_err("skb_copy_bits() failed - %d\n", err);
kfree(buf);
usb_free_urb(urb);
- kfree_skb(skb);
+ usb_autopm_put_interface_async(usb->usb.interface);
return err;
}
usb_fill_bulk_urb(urb, usb->usb.device, usb->usb.pipe.bulk.out,
@@ -801,11 +914,27 @@ static void usb_net_raw_ip_tx_urb_work(struct work_struct *work)
pr_debug("usb_net_raw_ip_tx_urb_work {\n");
/* check if tx urb(s) queued */
- if (!usb->usb.tx_urb && usb_anchor_empty(&usb->usb.tx_urb_deferred)) {
+ if (usb == NULL ||
+ (!usb->usb.tx_urb &&
+ usb_anchor_empty(&usb->usb.tx_urb_deferred))) {
pr_debug("%s: nothing to do!\n", __func__);
return;
}
+ /* check if usb interface disconnected */
+ if (!usb->usb.interface) {
+ pr_err("%s: not submitting tx urb %p -interface disconnected\n",
+ __func__, urb);
+ return;
+ }
+
+ /* check if suspended */
+ if (usb->susp_count > 0) {
+ pr_info("%s: usb->susp_count %d > 0 (suspended)\n",
+ __func__, usb->susp_count);
+ return;
+ }
+
/* submit queued tx urb(s) */
while ((urb = usb_get_from_anchor(&usb->usb.tx_urb_deferred))
!= (struct urb *) 0) {
@@ -821,33 +950,23 @@ static void usb_net_raw_ip_tx_urb_work(struct work_struct *work)
urb->transfer_buffer = (void *) 0;
}
usb_free_urb(urb);
+ usb->stats.tx_errors++;
continue;
}
/* autoresume before tx */
usb_mark_last_busy(usb->usb.device);
- err = usb_autopm_get_interface(usb->usb.interface);
- if (err < 0) {
- pr_err("%s: usb_autopm_get_interface(%p) failed %d\n",
- __func__, usb->usb.interface, err);
- if (urb->transfer_buffer) {
- kfree(urb->transfer_buffer);
- urb->transfer_buffer = (void *) 0;
- }
- usb_free_urb(urb);
- usb->stats.tx_errors++;
- continue;
- }
/* submit tx urb */
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
pr_err("%s: usb_submit_urb(%p) failed - err %d\n",
__func__, urb, err);
- usb_autopm_put_interface(usb->usb.interface);
+ usb_autopm_put_interface_async(usb->usb.interface);
if (urb->transfer_buffer) {
kfree(urb->transfer_buffer);
urb->transfer_buffer = (void *) 0;
}
usb_free_urb(urb);
+ usb->stats.tx_errors++;
continue;
}
/* free tx urb
@@ -865,7 +984,7 @@ static void usb_net_raw_ip_tx_urb_work(struct work_struct *work)
static void usb_net_raw_ip_tx_urb_comp(struct urb *urb)
{
- struct baseband_usb *usb = (struct baseband_usb *) urb->context;
+ struct baseband_usb *usb;
pr_debug("usb_net_raw_ip_tx_urb_comp {\n");
@@ -874,6 +993,7 @@ static void usb_net_raw_ip_tx_urb_comp(struct urb *urb)
pr_err("no urb\n");
return;
}
+ usb = (struct baseband_usb *)urb->context;
switch (urb->status) {
case 0:
break;
@@ -884,6 +1004,7 @@ static void usb_net_raw_ip_tx_urb_comp(struct urb *urb)
case -EPROTO:
pr_info("%s: tx urb %p - link shutdown %d\n",
__func__, urb, urb->status);
+ usb_autopm_put_interface_async(usb->usb.interface);
goto err_exit;
default:
pr_info("%s: tx urb %p - status %d\n",
@@ -896,6 +1017,7 @@ static void usb_net_raw_ip_tx_urb_comp(struct urb *urb)
usb->stats.tx_packets++;
usb->stats.tx_bytes += urb->transfer_buffer_length;
}
+
/* autosuspend after tx completed */
if (!usb->usb.interface) {
pr_err("%s: usb interface disconnected"
@@ -903,7 +1025,7 @@ static void usb_net_raw_ip_tx_urb_comp(struct urb *urb)
__func__);
goto err_exit;
}
- usb_autopm_put_interface(usb->usb.interface);
+ usb_autopm_put_interface_async(usb->usb.interface);
err_exit:
/* free tx urb transfer buffer */
@@ -911,7 +1033,6 @@ err_exit:
kfree(urb->transfer_buffer);
urb->transfer_buffer = (void *) 0;
}
-
pr_debug("usb_net_raw_ip_tx_urb_comp }\n");
}
@@ -934,6 +1055,7 @@ static int usb_net_raw_ip_init(void)
err = -1;
goto error_exit;
}
+ init_usb_anchor(&baseband_usb_net[i]->usb.tx_urb_deferred);
/* register network device */
usb_net_raw_ip_dev[i] = alloc_netdev(0,
BASEBAND_USB_NET_DEV_NAME,
@@ -966,7 +1088,6 @@ static int usb_net_raw_ip_init(void)
goto error_exit;
}
/* start usb tx */
- init_usb_anchor(&baseband_usb_net[i]->usb.tx_urb_deferred);
sprintf(name, "raw_ip_tx_wq-%d",
baseband_usb_net[i]->baseband_index);
baseband_usb_net[i]->usb.tx_workqueue
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index f1d88c5..802bbd6 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -278,6 +278,7 @@ source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
source "drivers/net/wireless/bcm4329/Kconfig"
source "drivers/net/wireless/bcmdhd/Kconfig"
+source "drivers/net/wireless/sd8797/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/ipw2x00/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 8ceae0a..3731f0e 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
obj-$(CONFIG_ATMEL) += atmel.o
-obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o
+obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o
obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o
obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o
@@ -61,3 +61,4 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/
obj-$(CONFIG_BCM4329) += bcm4329/
obj-$(CONFIG_BCMDHD) += bcmdhd/
+obj-$(CONFIG_SD8797) += sd8797/
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig
index 4c3461a..427cd99 100644
--- a/drivers/net/wireless/bcmdhd/Kconfig
+++ b/drivers/net/wireless/bcmdhd/Kconfig
@@ -77,3 +77,10 @@ config BCMDHD_INSMOD_NO_FW_LOAD
default n
---help---
Enable delayes firmware
+
+config BCMDHD_CUSTOM_REGULATORY_DOMAIN
+ bool "Enable Custom Regulatory Domain"
+ depends on BCMDHD
+ default y
+ ---help---
+ Use Custom Regulatory Domain set by driver.
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index 918e59f..85e93f7 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -30,6 +30,10 @@ ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y)
DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
endif
+ifeq ($(CONFIG_BCMDHD_CUSTOM_REGULATORY_DOMAIN),y)
+DHDCFLAGS += -DENABLE_CUSTOM_REGULATORY_DOMAIN
+endif
+
DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \
dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o \
bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index daa7d26..04affb5 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -4086,9 +4086,11 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
#endif
WIPHY_FLAG_4ADDR_STATION;
+#ifdef ENABLE_CUSTOM_REGULATORY_DOMAIN
WL_DBG(("Registering custom regulatory)\n"));
wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
+#endif
/* Now we can register wiphy with cfg80211 module */
err = wiphy_register(wdev->wiphy);
if (unlikely(err < 0)) {
diff --git a/drivers/net/wireless/sd8797/Kconfig b/drivers/net/wireless/sd8797/Kconfig
new file mode 100644
index 00000000..d823c85
--- /dev/null
+++ b/drivers/net/wireless/sd8797/Kconfig
@@ -0,0 +1,39 @@
+config SD8797
+ tristate "Marvel 8797 wireless cards support"
+ depends on MMC
+ default n
+ ---help---
+ This module adds support for wireless adapters based on
+ Marvel 8797 chipset.
+
+config STA_SUPPORT
+ depends on SD8797
+ bool "WLAN station support"
+ default y
+
+config UAP_SUPPORT
+ depends on SD8797
+ bool "Soft AP Support"
+ default y
+
+config WIFI_DIRECT_SUPPORT
+ depends on SD8797
+ bool "WiFi Direct Support"
+ default n
+
+config WIFI_DISPLAY_SUPPORT
+ depends on SD8797
+ bool "WiFi Display Support"
+ default n
+
+config STA_WEXT
+ depends on SD8797
+ depends on !CFG80211
+ bool "station wext support"
+ default n
+
+config UAP_WEXT
+ depends on SD8797
+ depends on !CFG80211
+ bool "UAP wext support"
+ default n
diff --git a/drivers/net/wireless/sd8797/Makefile b/drivers/net/wireless/sd8797/Makefile
new file mode 100644
index 00000000..3ef7038
--- /dev/null
+++ b/drivers/net/wireless/sd8797/Makefile
@@ -0,0 +1,176 @@
+# File: Makefile
+#
+# Copyright (C) 2008-2012, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License"). You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# A copy of the GPL is available in file gpl-2.0.txt accompanying in this
+# deliverables.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+# this warranty disclaimer.
+
+# Enable CFG80211 for STA
+ifeq ($(CONFIG_CFG80211),y)
+CONFIG_STA_CFG80211=y
+else
+ifeq ($(CONFIG_CFG80211),m)
+CONFIG_STA_CFG80211=y
+else
+CONFIG_STA_CFG80211=n
+endif
+endif
+
+# Enable CFG80211 for uAP
+ifeq ($(CONFIG_CFG80211),y)
+CONFIG_UAP_CFG80211=y
+else
+ifeq ($(CONFIG_CFG80211),m)
+CONFIG_UAP_CFG80211=y
+else
+CONFIG_UAP_CFG80211=n
+endif
+endif
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+
+EXTRA_CFLAGS += -Idrivers/net/wireless/sd8797/mlan
+EXTRA_CFLAGS += -DLINUX
+EXTRA_CFLAGS += -DFPNUM='"69"'
+EXTRA_CFLAGS += -DDEBUG_LEVEL1
+EXTRA_CFLAGS += -DPROC_DEBUG
+EXTRA_CFLAGS += -DSDIO_MULTI_PORT_TX_AGGR
+EXTRA_CFLAGS += -DSDIO_MULTI_PORT_RX_AGGR
+EXTRA_CFLAGS += -DSDIO_SUSPEND_RESUME
+EXTRA_CFLAGS += -DMMC_PM_KEEP_POWER
+EXTRA_CFLAGS += -DDFS_TESTING_SUPPORT
+EXTRA_CFLAGS += -DMFG_CMD_SUPPORT
+
+ifeq ($(CONFIG_64BIT), y)
+ EXTRA_CFLAGS += -DMLAN_64BIT
+endif
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ EXTRA_CFLAGS += -DSTA_SUPPORT
+ EXTRA_CFLAGS += -DREASSOCIATION
+ifeq ($(CONFIG_STA_WEXT),y)
+ EXTRA_CFLAGS += -DSTA_WEXT
+endif
+ifeq ($(CONFIG_STA_CFG80211),y)
+ EXTRA_CFLAGS += -DSTA_CFG80211
+endif
+else
+CONFIG_WIFI_DIRECT_SUPPORT=n
+CONFIG_WIFI_DISPLAY_SUPPORT=n
+CONFIG_STA_WEXT=n
+CONFIG_STA_CFG80211=n
+endif
+
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ EXTRA_CFLAGS += -DUAP_SUPPORT
+ifeq ($(CONFIG_UAP_WEXT),y)
+ EXTRA_CFLAGS += -DUAP_WEXT
+endif
+ifeq ($(CONFIG_UAP_CFG80211),y)
+ EXTRA_CFLAGS += -DUAP_CFG80211
+endif
+else
+CONFIG_WIFI_DIRECT_SUPPORT=n
+CONFIG_WIFI_DISPLAY_SUPPORT=n
+CONFIG_UAP_WEXT=n
+CONFIG_UAP_CFG80211=n
+endif
+
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+ EXTRA_CFLAGS += -DWIFI_DIRECT_SUPPORT
+endif
+ifeq ($(CONFIG_WIFI_DISPLAY_SUPPORT),y)
+ EXTRA_CFLAGS += -DWIFI_DISPLAY_SUPPORT
+endif
+
+ifeq ($(CONFIG_BIG_ENDIAN),y)
+ EXTRA_CFLAGS += -DBIG_ENDIAN_SUPPORT
+endif
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+MOALOBJS = mlinux/moal_main.o \
+ mlinux/moal_ioctl.o \
+ mlinux/moal_shim.o \
+ mlinux/moal_eth_ioctl.o
+
+MLANOBJS = mlan/mlan_shim.o mlan/mlan_init.o \
+ mlan/mlan_txrx.o \
+ mlan/mlan_cmdevt.o mlan/mlan_misc.o \
+ mlan/mlan_cfp.o \
+ mlan/mlan_module.o
+
+MLANOBJS += mlan/mlan_wmm.o
+MLANOBJS += mlan/mlan_sdio.o
+MLANOBJS += mlan/mlan_11n_aggr.o
+MLANOBJS += mlan/mlan_11n_rxreorder.o
+MLANOBJS += mlan/mlan_11n.o
+MLANOBJS += mlan/mlan_11d.o
+MLANOBJS += mlan/mlan_11h.o
+ifeq ($(CONFIG_STA_SUPPORT),y)
+MLANOBJS += mlan/mlan_meas.o
+MLANOBJS += mlan/mlan_scan.o \
+ mlan/mlan_sta_ioctl.o \
+ mlan/mlan_sta_rx.o \
+ mlan/mlan_sta_tx.o \
+ mlan/mlan_sta_event.o \
+ mlan/mlan_sta_cmd.o \
+ mlan/mlan_sta_cmdresp.o \
+ mlan/mlan_join.o
+ifeq ($(CONFIG_STA_WEXT),y)
+MOALOBJS += mlinux/moal_priv.o \
+ mlinux/moal_wext.o
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+MLANOBJS += mlan/mlan_uap_ioctl.o
+MLANOBJS += mlan/mlan_uap_cmdevent.o
+MLANOBJS += mlan/mlan_uap_txrx.o
+MOALOBJS += mlinux/moal_uap.o
+ifeq ($(CONFIG_UAP_WEXT),y)
+MOALOBJS += mlinux/moal_uap_priv.o
+MOALOBJS += mlinux/moal_uap_wext.o
+endif
+ifeq ($(CONFIG_STA_WEXT),y)
+MOALOBJS += mlinux/moal_wext.o
+endif
+endif
+ifeq ($(CONFIG_STA_CFG80211),y)
+MOALOBJS += mlinux/moal_cfg80211.o
+MOALOBJS += mlinux/moal_sta_cfg80211.o
+endif
+ifeq ($(CONFIG_UAP_CFG80211),y)
+MOALOBJS += mlinux/moal_cfg80211.o
+MOALOBJS += mlinux/moal_uap_cfg80211.o
+endif
+
+ifdef CONFIG_PROC_FS
+MOALOBJS += mlinux/moal_proc.o
+MOALOBJS += mlinux/moal_debug.o
+endif
+
+obj-m := mlan.o
+mlan-objs := $(MLANOBJS)
+MOALOBJS += mlinux/moal_sdio_mmc.o
+obj-m += sd8xxx.o
+sd8xxx-objs := $(MOALOBJS)
+
+###############################################################
+# End of file
diff --git a/drivers/net/wireless/sd8797/mlan/mlan.h b/drivers/net/wireless/sd8797/mlan/mlan.h
new file mode 100644
index 00000000..a341e15
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan.h
@@ -0,0 +1,35 @@
+/** @file mlan.h
+ *
+ * @brief This file declares all APIs that will be called from MOAL module.
+ * It also defines the data structures used for APIs between MLAN and MOAL.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+ 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h
+******************************************************/
+
+#ifndef _MLAN_H_
+#define _MLAN_H_
+
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+#include "mlan_ieee.h"
+
+#endif /* !_MLAN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11d.c b/drivers/net/wireless/sd8797/mlan/mlan_11d.c
new file mode 100644
index 00000000..fdc0d99
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11d.c
@@ -0,0 +1,1515 @@
+/** @file mlan_11d.c
+ *
+ * @brief This file contains functions for 802.11D.
+ *
+ * Copyright (C) 2008-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Region code mapping */
+typedef struct _region_code_mapping
+{
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+ /** Code */
+ t_u8 code;
+} region_code_mapping_t;
+
+/** Region code mapping table */
+static region_code_mapping_t region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+ {"JP ", 0x41}, /* Japan */
+ {"CN ", 0x50}, /* China */
+ {"JP ", 0xFE}, /* Japan */
+ {"JP ", 0xFF}, /* Japan special */
+};
+
+#ifdef STA_SUPPORT
+/** Default Tx power */
+#define TX_PWR_DEFAULT 10
+
+/** Universal region code */
+#define UNIVERSAL_REGION_CODE 0xff
+
+/* Following two structures define the supported channels */
+/** Channels for 802.11b/g */
+static chan_freq_power_t channel_freq_power_UN_BG[] = {
+ {1, 2412, TX_PWR_DEFAULT},
+ {2, 2417, TX_PWR_DEFAULT},
+ {3, 2422, TX_PWR_DEFAULT},
+ {4, 2427, TX_PWR_DEFAULT},
+ {5, 2432, TX_PWR_DEFAULT},
+ {6, 2437, TX_PWR_DEFAULT},
+ {7, 2442, TX_PWR_DEFAULT},
+ {8, 2447, TX_PWR_DEFAULT},
+ {9, 2452, TX_PWR_DEFAULT},
+ {10, 2457, TX_PWR_DEFAULT},
+ {11, 2462, TX_PWR_DEFAULT},
+ {12, 2467, TX_PWR_DEFAULT},
+ {13, 2472, TX_PWR_DEFAULT},
+ {14, 2484, TX_PWR_DEFAULT}
+};
+
+/** Channels for 802.11a/j */
+static chan_freq_power_t channel_freq_power_UN_AJ[] = {
+ {8, 5040, TX_PWR_DEFAULT},
+ {12, 5060, TX_PWR_DEFAULT},
+ {16, 5080, TX_PWR_DEFAULT},
+ {34, 5170, TX_PWR_DEFAULT},
+ {38, 5190, TX_PWR_DEFAULT},
+ {42, 5210, TX_PWR_DEFAULT},
+ {46, 5230, TX_PWR_DEFAULT},
+ {36, 5180, TX_PWR_DEFAULT},
+ {40, 5200, TX_PWR_DEFAULT},
+ {44, 5220, TX_PWR_DEFAULT},
+ {48, 5240, TX_PWR_DEFAULT},
+ {52, 5260, TX_PWR_DEFAULT},
+ {56, 5280, TX_PWR_DEFAULT},
+ {60, 5300, TX_PWR_DEFAULT},
+ {64, 5320, TX_PWR_DEFAULT},
+ {100, 5500, TX_PWR_DEFAULT},
+ {104, 5520, TX_PWR_DEFAULT},
+ {108, 5540, TX_PWR_DEFAULT},
+ {112, 5560, TX_PWR_DEFAULT},
+ {116, 5580, TX_PWR_DEFAULT},
+ {120, 5600, TX_PWR_DEFAULT},
+ {124, 5620, TX_PWR_DEFAULT},
+ {128, 5640, TX_PWR_DEFAULT},
+ {132, 5660, TX_PWR_DEFAULT},
+ {136, 5680, TX_PWR_DEFAULT},
+ {140, 5700, TX_PWR_DEFAULT},
+ {149, 5745, TX_PWR_DEFAULT},
+ {153, 5765, TX_PWR_DEFAULT},
+ {157, 5785, TX_PWR_DEFAULT},
+ {161, 5805, TX_PWR_DEFAULT},
+ {165, 5825, TX_PWR_DEFAULT},
+/* {240, 4920, TX_PWR_DEFAULT},
+ {244, 4940, TX_PWR_DEFAULT},
+ {248, 4960, TX_PWR_DEFAULT},
+ {252, 4980, TX_PWR_DEFAULT},
+channels for 11J JP 10M channel gap */
+};
+#endif /* STA_SUPPORT */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function converts region string to integer code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region Region string
+ * @param code [output] Region code
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_region_2_code(pmlan_adapter pmadapter, t_u8 * region, OUT t_u8 * code)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < size; i++) {
+ if (!memcmp(pmadapter, region_code_mapping[i].region,
+ region, COUNTRY_CODE_LEN)) {
+ *code = region_code_mapping[i].code;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function converts integer code to region string
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param code Region code
+ *
+ * @return Region string
+ */
+static t_u8 *
+wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < size; i++) {
+ if (region_code_mapping[i].code == code) {
+ LEAVE();
+ return (region_code_mapping[i].region);
+ }
+ }
+
+ LEAVE();
+ /* Default is US */
+ return (region_code_mapping[0].region);
+}
+
+/**
+ * @brief This function Checks if channel txpwr is learned from AP/IBSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band number
+ * @param chan Channel number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8
+wlan_11d_channel_known(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+ chan_power_11d_t *pchan_pwr = parsed_region_chan->chan_pwr;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 i = 0;
+ t_u8 ret = MFALSE;
+ mlan_private *pmpriv;
+
+ ENTER();
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) pchan_pwr,
+ sizeof(chan_power_11d_t) * no_of_chan);
+
+ /* Search channel */
+ for (i = 0; i < no_of_chan; i++) {
+ if (chan == pchan_pwr[i].chan && band == pchan_pwr[i].band) {
+ PRINTM(MINFO, "11D: Found channel:%d (band:%d)\n", chan, band);
+ ret = MTRUE;
+
+ if (band & BAND_A) {
+ /* If chan is a DFS channel, we need to see an AP on it */
+ if ((pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA))
+ && wlan_11h_radar_detect_required(pmpriv, chan)) {
+ PRINTM(MINFO, "11H: DFS channel %d, and ap_seen=%d\n",
+ chan, pchan_pwr[i].ap_seen);
+ ret = pchan_pwr[i].ap_seen;
+ }
+ }
+
+ LEAVE();
+ return ret;
+ }
+ }
+
+ PRINTM(MINFO, "11D: Could not find channel:%d (band:%d)\n", chan, band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates parsed_region_chan from Domain Info
+ * learned from AP/IBSS
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param region_chan Pointer to region_chan_t
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_generate_parsed_region_chan(pmlan_adapter pmadapter,
+ region_chan_t * region_chan,
+ parsed_region_chan_11d_t *
+ parsed_region_chan)
+{
+ chan_freq_power_t *cfp;
+ t_u8 i;
+
+ ENTER();
+
+ /* Region channel must be provided */
+ if (!region_chan) {
+ PRINTM(MWARN, "11D: region_chan is MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Get channel-frequency-power trio */
+ cfp = region_chan->pcfp;
+ if (!cfp) {
+ PRINTM(MWARN, "11D: cfp equal MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Set channel, band and power */
+ for (i = 0; i < region_chan->num_cfp; i++, cfp++) {
+ parsed_region_chan->chan_pwr[i].chan = (t_u8) cfp->channel;
+ parsed_region_chan->chan_pwr[i].band = region_chan->band;
+ parsed_region_chan->chan_pwr[i].pwr = (t_u8) cfp->max_tx_power;
+ PRINTM(MINFO, "11D: Chan[%d] Band[%d] Pwr[%d]\n",
+ parsed_region_chan->chan_pwr[i].chan,
+ parsed_region_chan->chan_pwr[i].band,
+ parsed_region_chan->chan_pwr[i].pwr);
+ }
+ parsed_region_chan->no_of_chan = region_chan->num_cfp;
+
+ PRINTM(MINFO, "11D: no_of_chan[%d]\n", parsed_region_chan->no_of_chan);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function generates domain_info from parsed_region_chan
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_generate_domain_info(pmlan_adapter pmadapter,
+ parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = MFALSE;
+ wlan_802_11d_domain_reg_t *domain_info = &pmadapter->domain_reg;
+
+ ENTER();
+
+ /* Should be only place that clear domain_reg (besides init) */
+ memset(pmadapter, domain_info, 0, sizeof(wlan_802_11d_domain_reg_t));
+
+ /* Set country code */
+ memcpy(pmadapter, domain_info->country_code,
+ wlan_11d_code_2_region(pmadapter, (t_u8) pmadapter->region_code),
+ COUNTRY_CODE_LEN);
+
+ PRINTM(MINFO, "11D: Number of channel = %d\n", no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ /* Set channel and power */
+ for (i = 0; i < no_of_chan; i++) {
+ if (!flag) {
+ flag = MTRUE;
+ next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (parsed_region_chan->chan_pwr[i].chan == next_chan + 1 &&
+ parsed_region_chan->chan_pwr[i].pwr == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan =
+ no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ no_of_parsed_chan = 1;
+ next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ }
+ }
+
+ if (flag) {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ }
+ domain_info->no_of_sub_band = no_of_sub_band;
+
+ PRINTM(MINFO, "11D: Number of sub-band =0x%x\n",
+ domain_info->no_of_sub_band);
+ HEXDUMP("11D: domain_info", (t_u8 *) domain_info,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(IEEEtypes_SubbandSet_t) * no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates the channel power table with the channel
+ * present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_update_chan_pwr_table(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i;
+ t_u8 tx_power = 0;
+ t_u8 chan;
+
+ ENTER();
+
+ chan = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ tx_power = wlan_get_txpwr_of_chan_from_cfp(pmpriv, chan);
+
+ if (!tx_power) {
+ PRINTM(MMSG, "11D: Invalid channel\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Check whether the channel already exists in channel power table of
+ parsed region */
+ for (i = 0; ((i < parsed_region_chan->no_of_chan) &&
+ (i < MAX_NO_OF_CHAN)); i++) {
+ if (parsed_region_chan->chan_pwr[i].chan == chan
+ && parsed_region_chan->chan_pwr[i].band == pbss_desc->bss_band) {
+ /* Channel already exists, use minimum of existing and tx_power */
+ parsed_region_chan->chan_pwr[i].pwr =
+ MIN(parsed_region_chan->chan_pwr[i].pwr, tx_power);
+ parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
+ break;
+ }
+ }
+
+ if (i == parsed_region_chan->no_of_chan && i < MAX_NO_OF_CHAN) {
+ /* Channel not found. Update the channel in the channel-power table */
+ parsed_region_chan->chan_pwr[i].chan = chan;
+ parsed_region_chan->chan_pwr[i].band = (t_u8) pbss_desc->bss_band;
+ parsed_region_chan->chan_pwr[i].pwr = tx_power;
+ parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
+ parsed_region_chan->no_of_chan++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds the no_of_chan-th chan after the first_chan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band
+ * @param first_chan First channel number
+ * @param no_of_chan Number of channels
+ * @param chan Pointer to the returned no_of_chan-th chan number
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8
+wlan_11d_get_chan(pmlan_adapter pmadapter, t_u8 band, t_u8 first_chan,
+ t_u8 no_of_chan, t_u8 * chan)
+{
+ chan_freq_power_t *cfp = MNULL;
+ t_u8 i;
+ t_u8 cfp_no = 0;
+
+ ENTER();
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ cfp = channel_freq_power_UN_BG;
+ cfp_no = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
+ } else if (band & (BAND_A | BAND_AN)) {
+ cfp = channel_freq_power_UN_AJ;
+ cfp_no = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
+ } else {
+ PRINTM(MERROR, "11D: Wrong Band[%d]\n", band);
+ LEAVE();
+ return MFALSE;
+ }
+ /* Locate the first_chan */
+ for (i = 0; i < cfp_no; i++) {
+ if (cfp && ((cfp + i)->channel == first_chan)) {
+ PRINTM(MINFO, "11D: first_chan found\n");
+ break;
+ }
+ }
+
+ if (i < cfp_no) {
+ /* Check if beyond the boundary */
+ if (i + no_of_chan < cfp_no) {
+ /* Get first_chan + no_of_chan */
+ *chan = (t_u8) (cfp + i + no_of_chan)->channel;
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function processes the country info present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_process_country_info(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i, j, num_chan_added = 0;
+
+ ENTER();
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* Parse 11D country info */
+ if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ &region_chan) != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (parsed_region_chan->no_of_chan != 0) {
+ /*
+ * Check if the channel number already exists in the
+ * chan-power table of parsed_region_chan
+ */
+ for (i = 0; (i < region_chan.no_of_chan && i < MAX_NO_OF_CHAN); i++) {
+ for (j = 0; (j < parsed_region_chan->no_of_chan &&
+ j < MAX_NO_OF_CHAN); j++) {
+ /*
+ * Channel already exists, update the tx power with new tx
+ * power, since country IE is valid here.
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ parsed_region_chan->chan_pwr[j].chan &&
+ region_chan.chan_pwr[i].band ==
+ parsed_region_chan->chan_pwr[j].band) {
+ parsed_region_chan->chan_pwr[j].pwr =
+ region_chan.chan_pwr[i].pwr;
+ break;
+ }
+ }
+
+ if (j == parsed_region_chan->no_of_chan && j < MAX_NO_OF_CHAN) {
+ /*
+ * Channel does not exist in the channel power table,
+ * update this new chan and tx_power to the channel power table
+ */
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].chan =
+ region_chan.chan_pwr[i].chan;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].band =
+ region_chan.chan_pwr[i].band;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].pwr =
+ region_chan.chan_pwr[i].pwr;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].ap_seen = MFALSE;
+ num_chan_added++;
+ }
+ }
+ parsed_region_chan->no_of_chan += num_chan_added;
+ } else {
+ /* Parsed region is empty, copy the first one */
+ memcpy(pmadapter, parsed_region_chan,
+ &region_chan, sizeof(parsed_region_chan_11d_t));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This helper function copies chan_power_11d_t element
+ *
+ * @param chan_dst Pointer to destination of chan_power
+ * @param chan_src Pointer to source of chan_power
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_copy_chan_power(chan_power_11d_t * chan_dst,
+ chan_power_11d_t * chan_src)
+{
+ ENTER();
+
+ chan_dst->chan = chan_src->chan;
+ chan_dst->band = chan_src->band;
+ chan_dst->pwr = chan_src->pwr;
+ chan_dst->ap_seen = chan_src->ap_seen;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sorts parsed_region_chan in ascending
+ * channel number.
+ *
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_sort_parsed_region_chan(parsed_region_chan_11d_t * parsed_region_chan)
+{
+ int i, j;
+ chan_power_11d_t temp;
+ chan_power_11d_t *pchan_power = parsed_region_chan->chan_pwr;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: Number of channel = %d\n",
+ parsed_region_chan->no_of_chan);
+
+ // Use insertion sort method
+ for (i = 1; i < parsed_region_chan->no_of_chan; i++) {
+ wlan_11d_copy_chan_power(&temp, pchan_power + i);
+ for (j = i; j > 0 && (pchan_power + j - 1)->chan > temp.chan; j--)
+ wlan_11d_copy_chan_power(pchan_power + j, pchan_power + j - 1);
+ wlan_11d_copy_chan_power(pchan_power + j, &temp);
+ }
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ LEAVE();
+ return;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function sends domain info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_send_domain_info(mlan_private * pmpriv, t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send cmd to FW to set domain info */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_buf, MNULL);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to download domain Info\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function overwrites domain_info
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param band Intended operating band
+ * @param country_code Intended country code
+ * @param num_sub_band Count of tuples in list below
+ * @param sub_band_list List of sub_band tuples
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_set_domain_info(mlan_private * pmpriv,
+ t_u8 band,
+ t_u8 country_code[COUNTRY_CODE_LEN],
+ t_u8 num_sub_band,
+ IEEEtypes_SubbandSet_t * sub_band_list)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ wlan_802_11d_domain_reg_t *pdomain = &pmadapter->domain_reg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(pmadapter, pdomain, 0, sizeof(wlan_802_11d_domain_reg_t));
+ memcpy(pmadapter, pdomain->country_code, country_code, COUNTRY_CODE_LEN);
+ pdomain->band = band;
+ pdomain->no_of_sub_band = num_sub_band;
+ memcpy(pmadapter, pdomain->sub_band, sub_band_list,
+ MIN(MRVDRV_MAX_SUBBAND_802_11D,
+ num_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function gets if priv is a station (STA)
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_is_station(mlan_private * pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief This function gets if 11D is enabled
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_11d_is_enabled(mlan_private * pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (pmpriv->state_11d.enable_11d == ENABLE_11D) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief Initialize interface variable for 11D
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11d_priv_init(mlan_private * pmpriv)
+{
+ wlan_802_11d_state_t *state = &pmpriv->state_11d;
+
+ ENTER();
+
+ /* Start in disabled mode */
+ state->enable_11d = DISABLE_11D;
+ if (!pmpriv->adapter->init_para.cfg_11d)
+ state->user_enable_11d = DEFAULT_11D_STATE;
+ else
+ state->user_enable_11d =
+ (pmpriv->adapter->init_para.cfg_11d == MLAN_INIT_PARA_DISABLED) ?
+ DISABLE_11D : ENABLE_11D;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Initialize device variable for 11D
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11d_init(mlan_adapter * pmadapter)
+{
+ ENTER();
+
+#ifdef STA_SUPPORT
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ memset(pmadapter, &(pmadapter->universal_channel), 0,
+ sizeof(region_chan_t));
+#endif
+ memset(pmadapter, &(pmadapter->domain_reg), 0,
+ sizeof(wlan_802_11d_domain_reg_t));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function enable/disable 11D
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param flag 11D status
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_enable(mlan_private * pmpriv, t_void * pioctl_buf, state_11d_t flag)
+{
+#ifdef STA_SUPPORT
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#endif
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable = flag;
+
+ ENTER();
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11D_i, (t_void *) pioctl_buf, &enable);
+
+ if (ret) {
+ PRINTM(MERROR, "11D: Failed to %s 11D\n",
+ (flag) ? "enable" : "disable");
+ }
+#ifdef STA_SUPPORT
+ else {
+ /* clear parsed table regardless of flag */
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ }
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure of
+ * command buffer
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd, t_u16 cmd_action)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11D_DOMAIN_INFO *pdomain_info = &pcmd->params.domain_info;
+ MrvlIEtypes_DomainParamSet_t *domain = &pdomain_info->domain;
+ t_u8 no_of_sub_band = pmadapter->domain_reg.no_of_sub_band;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: number of sub-band=0x%x\n", no_of_sub_band);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
+ pdomain_info->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ /* Dump domain info */
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *) pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* Set domain info fields */
+ domain->header.type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(pmadapter, domain->country_code,
+ pmadapter->domain_reg.country_code, sizeof(domain->country_code));
+
+ domain->header.len = ((no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t)) +
+ sizeof(domain->country_code));
+
+ if (no_of_sub_band) {
+ memcpy(pmadapter, domain->sub_band,
+ pmadapter->domain_reg.sub_band,
+ MIN(MRVDRV_MAX_SUBBAND_802_11D,
+ no_of_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
+
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) +
+ domain->header.len +
+ sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
+ } else {
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
+ }
+ domain->header.len = wlan_cpu_to_le16(domain->header.len);
+
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *) pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle response of CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp Pointer to command response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11d_domain_info(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP *domain_info =
+ &resp->params.domain_info_resp;
+ MrvlIEtypes_DomainParamSet_t *domain = &domain_info->domain;
+ t_u16 action = wlan_le16_to_cpu(domain_info->action);
+ t_u8 no_of_sub_band = 0;
+
+ ENTER();
+
+ /* Dump domain info response data */
+ HEXDUMP("11D: DOMAIN Info Rsp Data", (t_u8 *) resp, resp->size);
+
+ no_of_sub_band =
+ (t_u8) ((wlan_le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN)
+ / sizeof(IEEEtypes_SubbandSet_t));
+
+ PRINTM(MINFO, "11D Domain Info Resp: number of sub-band=%d\n",
+ no_of_sub_band);
+
+ if (no_of_sub_band > MRVDRV_MAX_SUBBAND_802_11D) {
+ PRINTM(MWARN, "11D: Invalid number of subbands %d returned!!\n",
+ no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (action) {
+ case HostCmd_ACT_GEN_SET: /* Proc Set Action */
+ break;
+ case HostCmd_ACT_GEN_GET:
+ break;
+ default:
+ PRINTM(MERROR, "11D: Invalid Action:%d\n", domain_info->action);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function parses country information for region channel
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param country_info Country information
+ * @param band Chan band
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
+ IEEEtypes_CountryInfoFullSet_t * country_info,
+ t_u8 band,
+ parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 no_of_sub_band, no_of_chan;
+ t_u8 last_chan, first_chan, cur_chan = 0;
+ t_u8 idx = 0;
+ t_u8 j, i;
+
+ ENTER();
+
+ /*
+ * Validation Rules:
+ * 1. Valid Region Code
+ * 2. First Chan increment
+ * 3. Channel range no overlap
+ * 4. Channel is valid?
+ * 5. Channel is supported by Region?
+ * 6. Others
+ */
+
+ HEXDUMP("country_info", (t_u8 *) country_info, 30);
+
+ /* Step 1: Check region_code */
+ if (!(*(country_info->country_code)) ||
+ (country_info->len <= COUNTRY_CODE_LEN)) {
+ /* No region info or wrong region info: treat as no 11D info */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ no_of_sub_band = (country_info->len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t);
+
+ for (j = 0, last_chan = 0; j < no_of_sub_band; j++) {
+
+ if (country_info->sub_band[j].first_chan <= last_chan) {
+ /* Step2&3: Check First Chan Num increment and no overlap */
+ PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n",
+ country_info->sub_band[j].first_chan, last_chan);
+ continue;
+ }
+
+ first_chan = country_info->sub_band[j].first_chan;
+ no_of_chan = country_info->sub_band[j].no_of_chan;
+
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < no_of_chan; i++) {
+ /* Step 4 : Channel is supported? */
+ if (wlan_11d_get_chan(pmadapter, band, first_chan, i, &cur_chan) ==
+ MFALSE) {
+ /* Chan is not found in UN table */
+ PRINTM(MWARN, "11D: channel is not supported: %d\n", i);
+ break;
+ }
+
+ last_chan = cur_chan;
+
+ /* Step 5: We don't need to check if cur_chan is supported by mrvl
+ in region */
+ parsed_region_chan->chan_pwr[idx].chan = cur_chan;
+ parsed_region_chan->chan_pwr[idx].band = band;
+ parsed_region_chan->chan_pwr[idx].pwr =
+ country_info->sub_band[j].max_tx_pwr;
+ idx++;
+ }
+
+ /* Step 6: Add other checking if any */
+ }
+
+ parsed_region_chan->no_of_chan = idx;
+
+ PRINTM(MINFO, "11D: number of channel=0x%x\n",
+ parsed_region_chan->no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan->chan_pwr,
+ sizeof(chan_power_11d_t) * idx);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function converts channel to frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param chan Channel number
+ * @param band Band
+ *
+ * @return Channel frequency
+ */
+t_u32
+wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band)
+{
+ chan_freq_power_t *cf;
+ t_u16 cnt;
+ t_u16 i;
+ t_u32 freq = 0;
+
+ ENTER();
+
+ /* Get channel-frequency-power trios */
+ if (band & (BAND_A | BAND_AN)) {
+ cf = channel_freq_power_UN_AJ;
+ cnt = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
+ } else {
+ cf = channel_freq_power_UN_BG;
+ cnt = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
+ }
+
+ /* Locate channel and return corresponding frequency */
+ for (i = 0; i < cnt; i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+
+ LEAVE();
+ return freq;
+}
+
+/**
+ * @brief This function setups scan channels
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ * @param band Band
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_11d_set_universaltable(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 size = sizeof(chan_freq_power_t);
+ t_u16 i = 0;
+
+ ENTER();
+
+ memset(pmadapter, pmadapter->universal_channel, 0,
+ sizeof(pmadapter->universal_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN))
+ /* If band B, G or N */
+ {
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ (t_u8) (sizeof(channel_freq_power_UN_BG) / size);
+ PRINTM(MINFO, "11D: BG-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_BG;
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ if (band & BAND_GN)
+ pmadapter->universal_channel[i].band = BAND_G;
+ else
+ pmadapter->universal_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+
+ if (band & (BAND_A | BAND_AN)) {
+ /* If band A */
+
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ sizeof(channel_freq_power_UN_AJ) / size;
+ PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
+
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ pmadapter->universal_channel[i].band = BAND_A;
+ i++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function calculates the scan type for channels
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band number
+ * @param chan Chan number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
+ */
+t_u8
+wlan_11d_get_scan_type(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 scan_type = MLAN_SCAN_TYPE_PASSIVE;
+
+ ENTER();
+
+ if (wlan_11d_channel_known(pmadapter, band, chan, parsed_region_chan)) {
+ /* Channel found */
+ PRINTM(MINFO, "11D: Channel found and doing Active Scan\n");
+ scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ } else
+ PRINTM(MINFO, "11D: Channel not found and doing Passive Scan\n");
+
+ LEAVE();
+ return scan_type;
+}
+
+/**
+ * @brief This function clears the parsed region table, if 11D is enabled
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_clear_parsedtable(mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_11d_is_enabled(pmpriv))
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ else
+ ret = MLAN_STATUS_FAILURE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates 11D info from user specified regioncode
+ * and download to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band to create
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_create_dnld_countryinfo(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *region_chan;
+ parsed_region_chan_11d_t parsed_region_chan;
+ t_u8 j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv)) {
+
+ PRINTM(MINFO, "11D: Band[%d]\n", band);
+
+ /* Update parsed_region_chan; download domain info to FW */
+
+ /* Find region channel */
+ for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) {
+ region_chan = &pmadapter->region_channel[j];
+
+ PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j,
+ region_chan->band);
+
+ if (!region_chan || !region_chan->valid || !region_chan->pcfp)
+ continue;
+ switch (region_chan->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_B:
+ case BAND_G:
+ case BAND_G | BAND_B:
+ case BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ /* Check if region channel found */
+ if (j >= MAX_REGION_CHANNEL_NUM) {
+ PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n", band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Generate parsed region channel info from region channel */
+ memset(pmadapter, &parsed_region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+ wlan_11d_generate_parsed_region_chan(pmadapter, region_chan,
+ &parsed_region_chan);
+
+ /* Generate domain info from parsed region channel info */
+ wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan);
+
+ /* Set domain info */
+ ret = wlan_11d_send_domain_info(pmpriv, MNULL);
+ if (ret) {
+ PRINTM(MERROR, "11D: Error sending domain info to FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function parses country info from AP and
+ * download country info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSS descriptor
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_parse_dnld_countryinfo(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t bssdesc_region_chan;
+ t_u32 i, j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv)) {
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+ memset(pmadapter, &bssdesc_region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+
+ memcpy(pmadapter, &region_chan,
+ &pmadapter->parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ if (pbss_desc) {
+ /* Parse domain info if available */
+ ret =
+ wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ &bssdesc_region_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ /* Update the channel-power table */
+ for (i = 0; ((i < bssdesc_region_chan.no_of_chan)
+ && (i < MAX_NO_OF_CHAN)); i++) {
+
+ for (j = 0; ((j < region_chan.no_of_chan)
+ && (j < MAX_NO_OF_CHAN)); j++) {
+ /*
+ * Channel already exists, use minimum of existing
+ * tx power and tx_power received from
+ * country info of the current AP
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ bssdesc_region_chan.chan_pwr[j].chan &&
+ region_chan.chan_pwr[i].band ==
+ bssdesc_region_chan.chan_pwr[j].band) {
+ region_chan.chan_pwr[j].pwr =
+ MIN(region_chan.chan_pwr[j].pwr,
+ bssdesc_region_chan.chan_pwr[i].pwr);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Generate domain info */
+ wlan_11d_generate_domain_info(pmadapter, &region_chan);
+
+ /* Set domain info */
+ ret = wlan_11d_send_domain_info(pmpriv, MNULL);
+ if (ret) {
+ PRINTM(MERROR, "11D: Error sending domain info to FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares domain info from scan table and
+ * downloads the domain info command to the FW.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_prepare_dnld_domain_info_cmd(mlan_private * pmpriv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ IEEEtypes_CountryInfoFullSet_t *pcountry_full = MNULL;
+ t_u32 idx;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv) && pmadapter->num_in_scan_table != 0) {
+ for (idx = 0; idx < pmadapter->num_in_scan_table; idx++) {
+ pcountry_full = &pmadapter->pscan_table[idx].country_info;
+
+ ret =
+ wlan_11d_update_chan_pwr_table(pmpriv,
+ &pmadapter->pscan_table[idx]);
+
+ if (*(pcountry_full->country_code) != 0 &&
+ (pcountry_full->len > COUNTRY_CODE_LEN)) {
+ /* Country info found in the BSS Descriptor */
+ ret =
+ wlan_11d_process_country_info(pmpriv,
+ &pmadapter->pscan_table[idx]);
+ }
+ }
+
+ /* Sort parsed_region_chan in ascending channel number */
+ wlan_11d_sort_parsed_region_chan(&pmadapter->parsed_region_chan);
+
+ /* Check if connected */
+ if (pmpriv->media_connected == MTRUE) {
+ ret =
+ wlan_11d_parse_dnld_countryinfo(pmpriv,
+ &pmpriv->curr_bss_params.
+ bss_descriptor);
+ } else {
+ ret = wlan_11d_parse_dnld_countryinfo(pmpriv, MNULL);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets up domain_reg and downloads CMD to FW
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_cfg_domain_info(IN pmlan_adapter pmadapter,
+ IN mlan_ioctl_req * pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11d_domain_info *domain_info = MNULL;
+ mlan_ds_11d_cfg *cfg_11d = MNULL;
+ t_u8 region_code = 0;
+
+ ENTER();
+
+ cfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ domain_info = &cfg_11d->param.domain_info;
+
+ /* Update region code and table based on country code */
+ if (wlan_11d_region_2_code(pmadapter, domain_info->country_code,
+ &region_code) == MLAN_STATUS_SUCCESS) {
+ pmadapter->region_code = region_code;
+ ret = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ }
+
+ wlan_11d_set_domain_info(pmpriv, domain_info->band,
+ domain_info->country_code,
+ domain_info->no_of_sub_band,
+ (IEEEtypes_SubbandSet_t *) domain_info->sub_band);
+ ret = wlan_11d_send_domain_info(pmpriv, pioctl_req);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT */
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief This function handles domain info data from UAP interface.
+ * Checks conditions, sets up domain_reg, then downloads CMD.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band interface is operating on
+ * @param domain_tlv Pointer to domain_info tlv
+ * @param pioctl_buf Pointer to the IOCTL buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_handle_uap_domain_info(mlan_private * pmpriv,
+ t_u8 band,
+ t_u8 * domain_tlv, t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ MrvlIEtypes_DomainParamSet_t *pdomain_tlv;
+ t_u8 num_sub_band = 0;
+ t_u8 region_code = 0;
+
+ ENTER();
+
+ pdomain_tlv = (MrvlIEtypes_DomainParamSet_t *) domain_tlv;
+
+ // update region code & table based on country string
+ if (wlan_11d_region_2_code(pmadapter, pdomain_tlv->country_code,
+ &region_code) == MLAN_STATUS_SUCCESS) {
+ pmadapter->region_code = region_code;
+ ret = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
+ }
+
+ num_sub_band = ((pdomain_tlv->header.len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t));
+
+ // TODO: don't just clobber pmadapter->domain_reg.
+ // Add some checking or merging between STA & UAP domain_info
+
+ wlan_11d_set_domain_info(pmpriv, band, pdomain_tlv->country_code,
+ num_sub_band, pdomain_tlv->sub_band);
+ ret = wlan_11d_send_domain_info(pmpriv, pioctl_buf);
+
+ LEAVE();
+ return ret;
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11h.c b/drivers/net/wireless/sd8797/mlan/mlan_11h.c
new file mode 100644
index 00000000..3a38979
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11h.c
@@ -0,0 +1,3208 @@
+/** @file mlan_11h.c
+ *
+ * @brief This file contains functions for 802.11H.
+ *
+ * Copyright (C) 2008-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_11h.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Default IBSS DFS recovery interval (in TBTTs); used for adhoc start */
+#define WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL 100
+
+/** Default 11h power constraint used to offset the maximum transmit power */
+#define WLAN_11H_TPC_POWERCONSTRAINT 0
+
+/** 11h TPC Power capability minimum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MIN 5
+
+/** 11h TPC Power capability maximum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MAX 20
+
+/** Regulatory requirement for the duration of a channel availability check */
+#define WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION 60000 /* in ms */
+
+/** Starting Frequency for 11A band */
+#define START_FREQ_11A_BAND 5000 /* in MHz */
+
+/** Regulatory requirement for the duration of a non-occupancy period */
+#define WLAN_11H_NON_OCCUPANCY_PERIOD 1800 /* in sec (30mins) */
+
+/** Maximum allowable age (seconds) on DFS report data */
+#define MAX_DFS_REPORT_USABLE_AGE_SEC (120) // 2 minutes
+
+/** Minimum delay for CHAN_SW IE to broadcast by FW */
+#define MIN_RDH_CHAN_SW_IE_PERIOD_MSEC (500) // 5 beacons @ 100ms
+
+/** Maximum delay for CHAN_SW IE to broadcast by FW */
+#define MAX_RDH_CHAN_SW_IE_PERIOD_MSEC (3000) // 5 beacons @ 600ms
+
+/** Maximum retries on selecting new random channel */
+#define MAX_RANDOM_CHANNEL_RETRIES (20)
+
+/** Maximum retries on selecting new random non-dfs channel */
+#define MAX_SWITCH_CHANNEL_RETRIES (30)
+
+/** Value for undetermined priv_curr_idx on first entry to new RDH stage */
+#define RDH_STAGE_FIRST_ENTRY_PRIV_IDX (0xff)
+
+/** Region codes 0x10, 0x20: channels 1 thru 11 supported */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_FCC = { 1, 11 };
+
+/** Region codes 0x30, 0x32, 0x41, 0x50: channels 1 thru 13 supported */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_EU = { 1, 13 };
+
+/** Region code 0x40: only channel 14 supported */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_JPN40 = { 14, 1 };
+
+/** JPN sub-band config : Start Channel = 8, NumChans = 3 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_JPN_bottom_band = { 8, 3 };
+
+/** U-NII sub-band config : Start Channel = 36, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_lower_band = { 36, 4 };
+
+/** U-NII sub-band config : Start Channel = 52, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_middle_band = { 52, 4 };
+
+/** U-NII sub-band config : Start Channel = 100, NumChans = 11 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band = { 100, 11 };
+
+/** U-NII sub-band config : Start Channel = 149, NumChans = 5 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_upper_band = { 149, 5 };
+
+/** Internally passed structure used to send a CMD_802_11_TPC_INFO command */
+typedef struct
+{
+ t_u8 chan; /**< Channel to which the power constraint applies */
+ t_u8 power_constraint; /**< Local power constraint to send to firmware */
+} wlan_11h_tpc_info_param_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Utility function to get a random number based on the underlying OS
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @return random integer
+ */
+static t_u32
+wlan_11h_get_random_num(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+
+ ENTER();
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+
+ LEAVE();
+ return ((usec << 16) | sec);
+}
+
+/**
+ * @brief Convert an IEEE formatted IE to 16-bit ID/Len Marvell
+ * proprietary format
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pout_buf Output parameter: Buffer to output Marvell formatted IE
+ * @param pin_ie Pointer to IEEE IE to be converted to Marvell format
+ *
+ * @return Number of bytes output to pout_buf parameter return
+ */
+static t_u32
+wlan_11h_convert_ieee_to_mrvl_ie(mlan_adapter * pmadapter,
+ t_u8 * pout_buf, const t_u8 * pin_ie)
+{
+ MrvlIEtypesHeader_t mrvl_ie_hdr;
+ t_u8 *ptmp_buf = pout_buf;
+
+ ENTER();
+ /* Assign the Element Id and Len to the Marvell struct attributes */
+ mrvl_ie_hdr.type = wlan_cpu_to_le16(pin_ie[0]);
+ mrvl_ie_hdr.len = wlan_cpu_to_le16(pin_ie[1]);
+
+ /* If the element ID is zero, return without doing any copying */
+ if (!mrvl_ie_hdr.type) {
+ LEAVE();
+ return 0;
+ }
+
+ /* Copy the header to the buffer pointer */
+ memcpy(pmadapter, ptmp_buf, &mrvl_ie_hdr, sizeof(mrvl_ie_hdr));
+
+ /* Increment the temp buffer pointer by the size appended */
+ ptmp_buf += sizeof(mrvl_ie_hdr);
+
+ /* Append the data section of the IE; length given by the IEEE IE length */
+ memcpy(pmadapter, ptmp_buf, pin_ie + 2, pin_ie[1]);
+
+ LEAVE();
+ /* Return the number of bytes appended to pout_buf */
+ return (sizeof(mrvl_ie_hdr) + pin_ie[1]);
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Setup the IBSS DFS element passed to the firmware in adhoc start
+ * and join commands
+ *
+ * The DFS Owner and recovery fields are set to be our MAC address and
+ * a predetermined constant recovery value. If we are joining an adhoc
+ * network, these values are replaced with the existing IBSS values.
+ * They are valid only when starting a new IBSS.
+ *
+ * The IBSS DFS Element is variable in size based on the number of
+ * channels supported in our current region.
+ *
+ * @param priv Private driver information structure
+ * @param pdfs Output parameter: Pointer to the IBSS DFS element setup by
+ * this function.
+ *
+ * @return
+ * - Length of the returned element in pdfs output parameter
+ * - 0 if returned element is not setup
+ */
+static t_u32
+wlan_11h_set_ibss_dfs_ie(mlan_private * priv, IEEEtypes_IBSS_DFS_t * pdfs)
+{
+ t_u8 num_chans = 0;
+ MeasRptBasicMap_t initial_map;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ /*
+ * A basic measurement report is included with each channel in the
+ * map field. Initial value for the map for each supported channel
+ * is with only the unmeasured bit set.
+ */
+ memset(adapter, &initial_map, 0x00, sizeof(initial_map));
+ initial_map.unmeasured = 1;
+
+ /* Set the DFS Owner and recovery interval fields */
+ memcpy(adapter, pdfs->dfs_owner, priv->curr_addr, sizeof(pdfs->dfs_owner));
+ pdfs->dfs_recovery_interval = WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL;
+
+ for (; (num_chans < adapter->parsed_region_chan.no_of_chan)
+ && (num_chans < WLAN_11H_MAX_IBSS_DFS_CHANNELS); num_chans++) {
+ pdfs->channel_map[num_chans].channel_number =
+ adapter->parsed_region_chan.chan_pwr[num_chans].chan;
+
+ /*
+ * Set the initial map field with a basic measurement
+ */
+ pdfs->channel_map[num_chans].rpt_map = initial_map;
+ }
+
+ /*
+ * If we have an established channel map, include it and return
+ * a valid DFS element
+ */
+ if (num_chans) {
+ PRINTM(MINFO, "11h: Added %d channels to IBSS DFS Map\n", num_chans);
+
+ pdfs->element_id = IBSS_DFS;
+ pdfs->len =
+ (sizeof(pdfs->dfs_owner) + sizeof(pdfs->dfs_recovery_interval)
+ + num_chans * sizeof(IEEEtypes_ChannelMap_t));
+
+ LEAVE();
+ return (pdfs->len + sizeof(pdfs->len) + sizeof(pdfs->element_id));
+ }
+
+ /* Ensure the element is zeroed out for an invalid return */
+ memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ LEAVE();
+ return 0;
+}
+#endif
+
+/**
+ * @brief Setup the Supported Channel IE sent in association requests
+ *
+ * The Supported Channels IE is required to be sent when the spectrum
+ * management capability (11h) is enabled. The element contains a
+ * starting channel and number of channels tuple for each sub-band
+ * the STA supports. This information is based on the operating region.
+ *
+ * @param priv Private driver information structure
+ * @param band Band in use
+ * @param psup_chan Output parameter: Pointer to the Supported Chan element
+ * setup by this function.
+ *
+ * @return
+ * - Length of the returned element in psup_chan output parameter
+ * - 0 if returned element is not setup
+ */
+static t_u16
+wlan_11h_set_supp_channels_ie(mlan_private * priv,
+ t_u8 band,
+ IEEEtypes_SupportedChannels_t * psup_chan)
+{
+ t_u16 num_subbands = 0;
+ t_u16 ret_len = 0;
+ t_u8 cfp_bg, cfp_a;
+
+ ENTER();
+ memset(priv->adapter, psup_chan, 0x00,
+ sizeof(IEEEtypes_SupportedChannels_t));
+
+ cfp_bg = cfp_a = priv->adapter->region_code;
+ if (!priv->adapter->region_code) {
+ /* Invalid region code, use CFP code */
+ cfp_bg = priv->adapter->cfp_code_bg;
+ cfp_a = priv->adapter->cfp_code_a;
+ }
+
+ if ((band & BAND_B) || (band & BAND_G)) {
+ /*
+ * Channels are contiguous in 2.4GHz, usually only one subband.
+ */
+ switch (cfp_bg) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ default:
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_FCC;
+ break;
+ case 0x30: /* Europe ETSI */
+ case 0x32: /* France */
+ case 0x41: /* Japan */
+ case 0x50: /* China */
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_EU;
+ break;
+ case 0x40: /* Japan */
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_JPN40;
+ break;
+ case 0xff: /* Japan special */
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_EU;
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_JPN40;
+ break;
+ }
+ } else if (band & BAND_A) {
+ /*
+ * Set the supported channel elements based on the region code,
+ * incrementing num_subbands for each sub-band we append to the
+ * element.
+ */
+ switch (cfp_a) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ case 0x32: /* France */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x30: /* Europe ETSI */
+ default:
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x50: /* China */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x40: /* Japan */
+ case 0x41: /* Japan */
+ case 0xff: /* Japan special */
+ psup_chan->subband[num_subbands++] = wlan_11h_JPN_bottom_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x1: /* Low band (5150-5250 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ break;
+ case 0x2: /* Lower middle band (5250-5350 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ break;
+ case 0x3: /* Upper middle band (5470-5725 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x4: /* High band (5725-5850 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x5: /* Low band (5150-5250 MHz) and High band
+ (5725-5850 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ }
+ }
+
+ /*
+ * If we have setup any supported subbands in the element, return a
+ * valid IE along with its size, else return 0.
+ */
+ if (num_subbands) {
+ psup_chan->element_id = SUPPORTED_CHANNELS;
+ psup_chan->len = num_subbands * sizeof(IEEEtypes_SupportChan_Subband_t);
+
+ ret_len = (t_u16) (psup_chan->len
+ + sizeof(psup_chan->len) +
+ sizeof(psup_chan->element_id));
+
+ HEXDUMP("11h: SupChan", (t_u8 *) psup_chan, ret_len);
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_ADAPT_REQ firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_802_11_TPC_ADAPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_cmd_tpc_request(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ ENTER();
+
+ memcpy(priv->adapter, &pcmd_ptr->params.tpc_req, pinfo_buf,
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+
+ pcmd_ptr->params.tpc_req.req.timeout =
+ wlan_cpu_to_le16(pcmd_ptr->params.tpc_req.req.timeout);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ) + S_DS_GEN;
+
+ HEXDUMP("11h: 11_TPC_ADAPT_REQ:", (t_u8 *) pcmd_ptr,
+ (t_u32) pcmd_ptr->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_INFO firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf wlan_11h_tpc_info_param_t passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_cmd_tpc_info(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const t_void * pinfo_buf)
+{
+ HostCmd_DS_802_11_TPC_INFO *ptpc_info = &pcmd_ptr->params.tpc_info;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint =
+ &ptpc_info->local_constraint;
+ MrvlIEtypes_PowerCapability_t *pcap = &ptpc_info->power_cap;
+
+ wlan_11h_device_state_t *pstate = &priv->adapter->state_11h;
+ const wlan_11h_tpc_info_param_t *ptpc_info_param =
+ (wlan_11h_tpc_info_param_t *) pinfo_buf;
+
+ ENTER();
+
+ pcap->min_power = pstate->min_tx_power_capability;
+ pcap->max_power = pstate->max_tx_power_capability;
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+
+ pconstraint->chan = ptpc_info_param->chan;
+ pconstraint->constraint = ptpc_info_param->power_constraint;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_INFO) + S_DS_GEN;
+
+ HEXDUMP("11h: TPC INFO", (t_u8 *) pcmd_ptr, (t_u32) pcmd_ptr->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_CHAN_SW_ANN firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_802_11_CHAN_SW_ANN passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_cmd_chan_sw_ann(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ const HostCmd_DS_802_11_CHAN_SW_ANN *pch_sw_ann =
+ (HostCmd_DS_802_11_CHAN_SW_ANN *) pinfo_buf;
+
+ ENTER();
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_CHAN_SW_ANN) + S_DS_GEN;
+
+ memcpy(priv->adapter, &pcmd_ptr->params.chan_sw_ann, pch_sw_ann,
+ sizeof(HostCmd_DS_802_11_CHAN_SW_ANN));
+
+ PRINTM(MINFO, "11h: ChSwAnn: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+ PRINTM(MINFO, "11h: ChSwAnn: Ch=%d, Cnt=%d, Mode=%d\n",
+ pch_sw_ann->new_chan, pch_sw_ann->switch_count,
+ pch_sw_ann->switch_mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_CHAN_REPORT_REQUEST firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_CHAN_RPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
+ */
+static mlan_status
+wlan_11h_cmd_chan_rpt_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ const HostCmd_DS_CHAN_RPT_REQ *pchan_rpt_req =
+ (HostCmd_DS_CHAN_RPT_REQ *) pinfo_buf;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ MrvlIEtypes_ChanRpt11hBasic_t *ptlv_basic;
+
+ ENTER();
+
+ if (pstate_dfs->dfs_check_pending) {
+ PRINTM(MERROR, "11h: ChanRptReq - previous CMD_CHAN_REPORT_REQUEST has"
+ " not returned its result yet (as EVENT_CHANNEL_READY)."
+ " This command will be dropped.\n");
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+ }
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_CHAN_RPT_REQ) + S_DS_GEN;
+
+ memcpy(priv->adapter, &pcmd_ptr->params.chan_rpt_req, pchan_rpt_req,
+ sizeof(HostCmd_DS_CHAN_RPT_REQ));
+
+ /* if DFS channel, add BASIC report TLV, and set radar bit */
+ if (wlan_11h_radar_detect_required(priv, pchan_rpt_req->chan_desc.chanNum)) {
+ ptlv_basic =
+ (MrvlIEtypes_ChanRpt11hBasic_t *) (((t_u8 *) (pcmd_ptr)) +
+ pcmd_ptr->size);
+ ptlv_basic->Header.type = wlan_cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC);
+ ptlv_basic->Header.len = wlan_cpu_to_le16(sizeof(MeasRptBasicMap_t));
+ memset(priv->adapter, &ptlv_basic->map, 0, sizeof(MeasRptBasicMap_t));
+ ptlv_basic->map.radar = 1;
+ pcmd_ptr->size += sizeof(MrvlIEtypes_ChanRpt11hBasic_t);
+ }
+
+ /* update dfs sturcture. dfs_check_pending is set when we receive CMD_RESP
+ == SUCCESS */
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_radar_found = MFALSE;
+ pstate_dfs->dfs_check_channel = pchan_rpt_req->chan_desc.chanNum;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set the local power capability and constraint TLV
+ *
+ * @param ppbuffer The buffer to add these two TLVs
+ * @param channel Channel to which the power constraint applies
+ * @param power_constraint Power constraint to be applied on the channel
+ * @param min_tx_power_capability Min. Tx Power in Power Capability IE
+ * @param max_tx_power_capability Max. Tx Power in Power Capability IE
+ *
+ * @return The len increased
+ */
+static t_u32
+wlan_11h_set_local_power_constraint_tlv(t_u8 ** ppbuffer,
+ t_u8 channel,
+ t_u8 power_constraint,
+ t_u8 min_tx_power_capability,
+ t_u8 max_tx_power_capability)
+{
+ MrvlIEtypes_PowerCapability_t *pcap;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint;
+ t_u8 *startPtr = MNULL;
+
+ ENTER();
+
+ /* Null Checks */
+ if ((ppbuffer == MNULL) || (((t_u8 *) (*ppbuffer)) == MNULL)) {
+ LEAVE();
+ return 0;
+ }
+
+ startPtr = (t_u8 *) (*ppbuffer);
+
+ PRINTM(MINFO,
+ "11h: Set local power constraint = %d channel=%d min_tx_pwr=%d max_tx_pwr=%d\n",
+ power_constraint, channel, min_tx_power_capability,
+ max_tx_power_capability);
+
+ pcap = (MrvlIEtypes_PowerCapability_t *) * ppbuffer;
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->min_power = min_tx_power_capability;
+ pcap->max_power = max_tx_power_capability;
+ *ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
+
+ pconstraint = (MrvlIEtypes_LocalPowerConstraint_t *) * ppbuffer;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+ pconstraint->chan = channel;
+ pconstraint->constraint = power_constraint;
+ *ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
+
+ LEAVE();
+ return (t_u32) (*ppbuffer - startPtr);
+}
+
+/**
+ * @brief Utility function to process a join to an infrastructure BSS
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param band Band on which we are joining the BSS
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static t_u32
+wlan_11h_process_infra_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ t_u8 band,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ MrvlIEtypesHeader_t ie_header;
+ IEEEtypes_SupportedChannels_t sup_chan_ie;
+ t_u32 ret_len = 0;
+ t_u16 sup_chan_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if ((ppbuffer == MNULL) || (((t_u8 *) (*ppbuffer)) == MNULL)) {
+ LEAVE();
+ return 0;
+ }
+
+ ret_len += wlan_11h_set_local_power_constraint_tlv(ppbuffer, (t_u8) channel,
+ (t_u8) p11h_bss_info->
+ power_constraint.
+ local_constraint,
+ (t_u8) priv->adapter->
+ state_11h.
+ min_tx_power_capability,
+ (t_u8) priv->adapter->
+ state_11h.
+ max_tx_power_capability);
+
+ /* Setup the Supported Channels IE */
+ sup_chan_len = wlan_11h_set_supp_channels_ie(priv, band, &sup_chan_ie);
+
+ /*
+ * If we returned a valid Supported Channels IE, wrap and append it
+ */
+ if (sup_chan_len) {
+ /* Wrap the supported channels IE with a passthrough TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = sup_chan_len;
+ memcpy(priv->adapter, *ppbuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the supported channels IE to the output buf, advance pointer */
+ memcpy(priv->adapter, *ppbuffer, &sup_chan_ie, sup_chan_len);
+ *ppbuffer += sup_chan_len;
+ ret_len += sup_chan_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Utility function to process a start or join to an adhoc network
+ *
+ * Add the elements to the TLV buffer needed in the start/join adhoc commands:
+ * - IBSS DFS IE
+ * - Quiet IE
+ *
+ * Also send the local constraint to the firmware in a TPC_INFO command.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param channel Channel on which we are starting/joining the IBSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response. NULL
+ * indicates we are starting the adhoc network
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static t_u32
+wlan_11h_process_adhoc(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ IEEEtypes_IBSS_DFS_t dfs_elem;
+ t_u32 size_appended;
+ t_u32 ret_len = 0;
+ t_s8 local_constraint = 0;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ /* Format our own IBSS DFS Element. Include our channel map fields */
+ wlan_11h_set_ibss_dfs_ie(priv, &dfs_elem);
+#endif
+
+ if (p11h_bss_info) {
+ /*
+ * Copy the DFS Owner/Recovery Interval from the BSS we are joining
+ */
+ memcpy(adapter, dfs_elem.dfs_owner,
+ p11h_bss_info->ibss_dfs.dfs_owner, sizeof(dfs_elem.dfs_owner));
+ dfs_elem.dfs_recovery_interval =
+ p11h_bss_info->ibss_dfs.dfs_recovery_interval;
+ }
+
+ /* Append the dfs element to the TLV buffer */
+ size_appended =
+ wlan_11h_convert_ieee_to_mrvl_ie(adapter, (t_u8 *) * ppbuffer,
+ (t_u8 *) & dfs_elem);
+
+ HEXDUMP("11h: IBSS-DFS", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+
+ /*
+ * Check to see if we are joining a network. Join is indicated by the
+ * BSS Info pointer being valid (not NULL)
+ */
+ if (p11h_bss_info) {
+ /*
+ * If there was a quiet element, include it in adhoc join command
+ */
+ if (p11h_bss_info->quiet.element_id == QUIET) {
+ size_appended
+ = wlan_11h_convert_ieee_to_mrvl_ie(adapter, (t_u8 *) * ppbuffer,
+ (t_u8 *) & p11h_bss_info->
+ quiet);
+ HEXDUMP("11h: Quiet", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+
+ /* Copy the local constraint from the network */
+ local_constraint = p11h_bss_info->power_constraint.local_constraint;
+ } else {
+ /*
+ * If we are the adhoc starter, we can add a quiet element
+ */
+ if (adapter->state_11h.quiet_ie.quiet_period) {
+ size_appended =
+ wlan_11h_convert_ieee_to_mrvl_ie(adapter, (t_u8 *) * ppbuffer,
+ (t_u8 *) & adapter->state_11h.
+ quiet_ie);
+ HEXDUMP("11h: Quiet", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+ /* Use the local_constraint configured in the driver state */
+ local_constraint = adapter->state_11h.usr_def_power_constraint;
+ }
+
+ PRINTM(MINFO, "WEILIE 1: ppbuffer = %p\n", *ppbuffer);
+
+ ret_len +=
+ wlan_11h_set_local_power_constraint_tlv(ppbuffer, (t_u8) channel,
+ (t_u8) local_constraint,
+ (t_u8) priv->adapter->state_11h.
+ min_tx_power_capability,
+ (t_u8) priv->adapter->state_11h.
+ max_tx_power_capability);
+ PRINTM(MINFO, "WEILIE 2: ppbuffer = %p\n", *ppbuffer);
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Return whether the driver has enabled 11h for the interface
+ *
+ * Association/Join commands are dynamic in that they enable 11h in the
+ * driver/firmware when they are detected in the existing BSS.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h is enabled
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_enabled(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->intf_state_11h.is_11h_enabled);
+}
+
+/**
+ * @brief Return whether the device has activated slave radar detection.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if slave radar detection is enabled in firmware
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_slave_radar_det_active(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->adapter->state_11h.is_slave_radar_det_active);
+}
+
+/**
+ * @brief Return whether the slave interface is active, and on DFS channel.
+ * priv is assumed to already be a dfs slave interface, doesn't check this.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if priv is slave, and meets both conditions
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_slave_active_on_dfs_chan(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ if ((priv->media_connected == MTRUE) &&
+ (priv->curr_bss_params.band & BAND_A) &&
+ wlan_11h_radar_detect_required(priv,
+ priv->curr_bss_params.bss_descriptor.
+ channel))
+ ret = MTRUE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Return whether the master interface is active, and on DFS channel.
+ * priv is assumed to already be a dfs master interface, doesn't check this.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if priv is master, and meets both conditions
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_master_active_on_dfs_chan(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ /* Ad-hoc creator */
+ if (((priv->media_connected == MTRUE)
+ || (priv->adhoc_state == ADHOC_STARTING)) &&
+ (priv->adapter->adhoc_start_band & BAND_A) &&
+ wlan_11h_radar_detect_required(priv, priv->adhoc_channel))
+ ret = MTRUE;
+ } else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /* UAP */
+#ifdef UAP_SUPPORT
+ if ((priv->uap_bss_started == MTRUE) &&
+ (priv->uap_state_chan_cb.band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(priv,
+ priv->uap_state_chan_cb.channel))
+ ret = MTRUE;
+#endif
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Determine if priv is DFS Master interface
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool
+wlan_11h_is_dfs_master(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ /* UAP: all are master */
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ ret = MTRUE;
+ }
+ /* STA: only ad-hoc creator is master */
+ else if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->bss_mode == MLAN_BSS_MODE_IBSS) &&
+ (priv->adhoc_state == ADHOC_STARTED ||
+ priv->adhoc_state == ADHOC_STARTING)) {
+ ret = MTRUE;
+ }
+ /* all other cases = slave interface */
+ LEAVE();
+ return ret;
+}
+
+/* Need this as function to pass to wlan_count_priv_cond() */
+/**
+ * @brief Determine if priv is DFS Slave interface
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+
+static t_bool
+wlan_11h_is_dfs_slave(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+ ENTER();
+ ret = !wlan_11h_is_dfs_master(priv);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if interface is active.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool
+wlan_is_intf_active(mlan_private * pmpriv)
+{
+ t_bool ret = MFALSE;
+ ENTER();
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ /* NOTE: UAP's media_connected == true only after first STA associated.
+ Need different variable to tell if UAP has been started. */
+ ret = pmpriv->uap_bss_started;
+ else
+#endif
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ ret = pmpriv->media_connected;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets current radar detect flags
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return 11H MIB setting for radar detect
+ */
+static t_u32
+wlan_11h_get_current_radar_detect_flags(mlan_adapter * pmadapter)
+{
+ t_u32 radar_det_flags = 0;
+
+ ENTER();
+ if (pmadapter->state_11h.is_master_radar_det_active)
+ radar_det_flags |= MASTER_RADAR_DET_MASK;
+ if (pmadapter->state_11h.is_slave_radar_det_active)
+ radar_det_flags |= SLAVE_RADAR_DET_MASK;
+
+ PRINTM(MINFO, "%s: radar_det_state_curr=0x%x\n",
+ __FUNCTION__, radar_det_flags);
+
+ LEAVE();
+ return radar_det_flags;
+}
+
+/**
+ * @brief This function checks if radar detect flags have/should be changed.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pnew_state Output param with new state, if return MTRUE.
+ *
+ * @return MTRUE (need update) or MFALSE (no change in flags)
+ */
+static t_bool
+wlan_11h_check_radar_det_state(mlan_adapter * pmadapter, OUT t_u32 * pnew_state)
+{
+ t_u32 radar_det_state_new = 0;
+ t_bool ret;
+
+ ENTER();
+ PRINTM(MINFO, "%s: master_radar_det_pending=%d, "
+ " slave_radar_det_pending=%d\n", __FUNCTION__,
+ pmadapter->state_11h.master_radar_det_enable_pending,
+ pmadapter->state_11h.slave_radar_det_enable_pending);
+
+ /* new state comes from evaluating interface states & pending starts */
+ if (pmadapter->state_11h.master_radar_det_enable_pending ||
+ (wlan_count_priv_cond(pmadapter,
+ wlan_11h_is_master_active_on_dfs_chan,
+ wlan_11h_is_dfs_master) > 0))
+ radar_det_state_new |= MASTER_RADAR_DET_MASK;
+ if (pmadapter->state_11h.slave_radar_det_enable_pending ||
+ (wlan_count_priv_cond(pmadapter,
+ wlan_11h_is_slave_active_on_dfs_chan,
+ wlan_11h_is_dfs_slave) > 0))
+ radar_det_state_new |= SLAVE_RADAR_DET_MASK;
+
+ PRINTM(MINFO, "%s: radar_det_state_new=0x%x\n",
+ __FUNCTION__, radar_det_state_new);
+
+ /* now compare flags with current state */
+ ret = (wlan_11h_get_current_radar_detect_flags(pmadapter)
+ != radar_det_state_new) ? MTRUE : MFALSE;
+ if (ret)
+ *pnew_state = radar_det_state_new;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Determine if mlan_private list only contains UAP interface(s)
+ *
+ * @param priv_list List of mlan_private pointers
+ * @param priv_list_count Number of mlan_privates in above list
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool
+wlan_only_uap_priv_in_list(mlan_private ** priv_list, t_u8 priv_list_count)
+{
+#if defined(STA_SUPPORT) && !defined(UAP_SUPPORT)
+ return MFALSE;
+#else
+ t_u8 uap_count = 0;
+ t_u8 sta_count = 0;
+ t_u8 i;
+
+ ENTER();
+ for (i = 0; i < priv_list_count; i++) {
+ if (GET_BSS_ROLE(priv_list[i]) == MLAN_BSS_ROLE_UAP)
+ uap_count++;
+ else
+ sta_count++;
+ }
+
+ LEAVE();
+ return ((uap_count > 0) && (sta_count == 0)) ? MTRUE : MFALSE;
+#endif
+}
+
+/**
+ * @brief Prepare ioctl for add/remove CHAN_SW IE - RADAR_DETECTED event handling
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to completed mlan_ioctl_req (allocated inside)
+ * @param is_adding_ie CHAN_SW IE is to be added (MTRUE), or removed (MFALSE)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11h_prepare_custom_ie_chansw(IN mlan_adapter * pmadapter,
+ OUT mlan_ioctl_req ** ppioctl_req,
+ IN t_bool is_adding_ie)
+{
+ mlan_ioctl_req *pioctl_req = MNULL;
+ mlan_ds_misc_cfg *pds_misc_cfg = MNULL;
+ custom_ie *pcust_chansw_ie = MNULL;
+ IEEEtypes_ChanSwitchAnn_t *pchansw_ie = MNULL;
+ mlan_status ret;
+
+ ENTER();
+
+ if (pmadapter == MNULL || ppioctl_req == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* allocate buffer for mlan_ioctl_req and mlan_ds_misc_cfg */
+ /* FYI - will be freed as part of cmd_response handler */
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ioctl_req) +
+ sizeof(mlan_ds_misc_cfg),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pioctl_req);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Could not allocate ioctl req\n", __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pds_misc_cfg = (mlan_ds_misc_cfg *) ((t_u8 *) pioctl_req +
+ sizeof(mlan_ioctl_req));
+
+ /* prepare mlan_ioctl_req */
+ memset(pmadapter, pioctl_req, 0x00, sizeof(mlan_ioctl_req));
+ pioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ pioctl_req->action = MLAN_ACT_SET;
+ pioctl_req->pbuf = (t_u8 *) pds_misc_cfg;
+ pioctl_req->buf_len = sizeof(mlan_ds_misc_cfg);
+
+ /* prepare mlan_ds_misc_cfg */
+ memset(pmadapter, pds_misc_cfg, 0x00, sizeof(mlan_ds_misc_cfg));
+ pds_misc_cfg->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ pds_misc_cfg->param.cust_ie.type = TLV_TYPE_MGMT_IE;
+ pds_misc_cfg->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
+
+ /* configure custom_ie api settings */
+ pcust_chansw_ie =
+ (custom_ie *) & pds_misc_cfg->param.cust_ie.ie_data_list[0];
+ pcust_chansw_ie->ie_index = 0xffff; /* Auto index */
+ pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
+ pcust_chansw_ie->mgmt_subtype_mask = (is_adding_ie)
+ ? MBIT(8) | MBIT(5) /* add IE for BEACON | PROBE_RSP */
+ : 0; /* remove IE */
+
+ /* prepare CHAN_SW IE inside ioctl */
+ pchansw_ie = (IEEEtypes_ChanSwitchAnn_t *) pcust_chansw_ie->ie_buffer;
+ pchansw_ie->element_id = CHANNEL_SWITCH_ANN;
+ pchansw_ie->len =
+ sizeof(IEEEtypes_ChanSwitchAnn_t) - sizeof(IEEEtypes_Header_t);
+ pchansw_ie->chan_switch_mode = 1; /* STA should not transmit */
+ pchansw_ie->new_channel_num = pmadapter->state_rdh.new_channel;
+ pchansw_ie->chan_switch_count = 0; /* simplification */
+
+ pds_misc_cfg->param.cust_ie.len += pcust_chansw_ie->ie_length;
+ DBG_HEXDUMP(MCMD_D, "11h: custom_ie containing CHAN_SW IE",
+ (t_u8 *) pcust_chansw_ie, pds_misc_cfg->param.cust_ie.len);
+
+ /* assign output pointer before returning */
+ *ppioctl_req = pioctl_req;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef UAP_SUPPORT
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and 5GHz band is selected in band_config
+ * return a random channel in A band, else one from BG band.
+ *
+ * @param priv Private driver information structure
+ * @param uap_band_cfg Private driver information structure
+ *
+ * @return Starting channel
+ */
+static t_u8
+wlan_11h_get_uap_start_channel(mlan_private * priv, t_u8 uap_band_cfg)
+{
+ t_u8 start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ t_u32 region;
+ t_u32 rand_entry;
+ region_chan_t *chn_tbl;
+ t_u8 rand_tries = 0;
+
+ // TODO: right now mostly a copy of wlan_11h_get_adhoc_start_channel.
+ // Improve to be more specfic to UAP, e.g.
+ // 1. take into account COUNTRY_CODE -> region_code
+ // 2. check domain_info for value channels
+
+ ENTER();
+
+ /*
+ * Set start_chn to the Default. Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if (uap_band_cfg & UAP_BAND_CONFIG_5GHZ) {
+ /*
+ * Set default to the A Band default. Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM); region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band */
+ if (chn_tbl->valid
+ && chn_tbl->region == adapter->region_code
+ && chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random number and
+ * use it to pick an entry in the table between 0
+ * and the number of channels in the table (NumCFP).
+ */
+ do {
+ rand_entry =
+ wlan_11h_get_random_num(adapter) % chn_tbl->num_cfp;
+ start_chn = (t_u8) chn_tbl->pcfp[rand_entry].channel;
+ } while (wlan_11h_is_channel_under_nop(adapter, start_chn)
+ && (++rand_tries < MAX_RANDOM_CHANNEL_RETRIES));
+ }
+ }
+ }
+ }
+
+ PRINTM(MCMD_D, "11h: UAP Get Start Channel %d\n", start_chn);
+ LEAVE();
+ return start_chn;
+}
+#endif /* UAP_SUPPORT */
+
+#ifdef DEBUG_LEVEL1
+static const char *DFS_TS_REPR_STRINGS[] = { "",
+ "NOP_start",
+ "CAC_completed"
+};
+#endif
+
+/**
+ * @brief Search for a dfs timestamp in the list with desired channel.
+ *
+ * Assumes there will only be one timestamp per channel in the list.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param channel Channel number
+ *
+ * @return Pointer to timestamp if found, or MNULL
+ */
+static wlan_dfs_timestamp_t *
+wlan_11h_find_dfs_timestamp(mlan_adapter * pmadapter, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pts = MNULL, *pts_found = MNULL;
+
+ ENTER();
+ pts = (wlan_dfs_timestamp_t *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.
+ dfs_ts_head, MNULL, MNULL);
+
+ while (pts &&
+ pts != (wlan_dfs_timestamp_t *) & pmadapter->state_dfs.dfs_ts_head) {
+ PRINTM(MINFO,
+ "dfs_timestamp(@ %p) - chan=%d, repr=%d(%s),"
+ " time(sec.usec)=%lu.%06lu\n", pts, pts->channel,
+ pts->represents, DFS_TS_REPR_STRINGS[pts->represents],
+ pts->ts_sec, pts->ts_usec);
+
+ if (pts->channel == channel) {
+ pts_found = pts;
+ break;
+ }
+ pts = pts->pnext;
+ }
+
+ LEAVE();
+ return pts_found;
+}
+
+/**
+ * @brief Removes dfs timestamp from list.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pdfs_ts Pointer to dfs_timestamp to remove
+ */
+static t_void
+wlan_11h_remove_dfs_timestamp(mlan_adapter * pmadapter,
+ wlan_dfs_timestamp_t * pdfs_ts)
+{
+ ENTER();
+ // dequeue and delete timestamp
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.dfs_ts_head,
+ (pmlan_linked_list) pdfs_ts, MNULL, MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pdfs_ts);
+ LEAVE();
+}
+
+/**
+ * @brief Add a dfs timestamp to the list
+ *
+ * Assumes there will only be one timestamp per channel in the list,
+ * and that timestamp modes (represents) are mutually exclusive.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param repr Timestamp 'represents' value (see _dfs_timestamp_repr_e)
+ * @param channel Channel number
+ *
+ * @return Pointer to timestamp if found, or MNULL
+ */
+static mlan_status
+wlan_11h_add_dfs_timestamp(mlan_adapter * pmadapter, t_u8 repr, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pdfs_ts = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
+
+ if (!pdfs_ts) {
+ // need to allocate new timestamp
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(wlan_dfs_timestamp_t),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pdfs_ts);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pdfs_ts) {
+ PRINTM(MERROR, "%s(): Could not allocate dfs_ts\n", __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, (t_u8 *) pdfs_ts, 0, sizeof(wlan_dfs_timestamp_t));
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.dfs_ts_head,
+ (pmlan_linked_list) pdfs_ts, MNULL, MNULL);
+ pdfs_ts->channel = channel;
+ }
+ // (else, use existing timestamp for channel; see assumptions above)
+
+ // update params
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pdfs_ts->ts_sec,
+ &pdfs_ts->ts_usec);
+ pdfs_ts->represents = repr;
+
+ PRINTM(MCMD_D, "11h: add/update dfs_timestamp - chan=%d, repr=%d(%s),"
+ " time(sec.usec)=%lu.%06lu\n", pdfs_ts->channel,
+ pdfs_ts->represents, DFS_TS_REPR_STRINGS[pdfs_ts->represents],
+ pdfs_ts->ts_sec, pdfs_ts->ts_usec);
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief Return whether the device has activated master radar detection.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if master radar detection is enabled in firmware
+ * - MFALSE otherwise
+ */
+t_bool
+wlan_11h_is_master_radar_det_active(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->adapter->state_11h.is_master_radar_det_active);
+}
+
+/**
+ * @brief Configure master radar detection.
+ * Call wlan_11h_check_update_radar_det_state() afterwards
+ * to push this to firmware.
+ *
+ * @param priv Private driver information structure
+ * @param enable Whether to enable or disable master radar detection
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_check_update_radar_det_state
+ */
+mlan_status
+wlan_11h_config_master_radar_det(mlan_private * priv, t_bool enable)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (wlan_11h_is_dfs_master(priv) &&
+ priv->adapter->init_para.dfs_master_radar_det_en) {
+ priv->adapter->state_11h.master_radar_det_enable_pending = enable;
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure slave radar detection.
+ * Call wlan_11h_check_update_radar_det_state() afterwards
+ * to push this to firmware.
+ *
+ * @param priv Private driver information structure
+ * @param enable Whether to enable or disable slave radar detection
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_check_update_radar_det_state
+ */
+mlan_status
+wlan_11h_config_slave_radar_det(mlan_private * priv, t_bool enable)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (wlan_11h_is_dfs_slave(priv) &&
+ priv->adapter->init_para.dfs_slave_radar_det_en) {
+ priv->adapter->state_11h.slave_radar_det_enable_pending = enable;
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Checks all interfaces and determines if radar_detect flag states
+ * have/should be changed. If so, sends SNMP_MIB 11H command to FW.
+ * Call this function on any interface enable/disable/channel change.
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS (update or not)
+ * or MLAN_STATUS_FAILURE (cmd failure)
+ *
+ * @sa wlan_11h_check_radar_det_state
+ */
+mlan_status
+wlan_11h_check_update_radar_det_state(mlan_private * pmpriv)
+{
+ t_u32 new_radar_det_state = 0;
+ t_u32 mib_11h = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_11h_check_radar_det_state(pmpriv->adapter, &new_radar_det_state)) {
+ PRINTM(MCMD_D, "%s: radar_det_state being updated.\n", __FUNCTION__);
+
+ mib_11h |= new_radar_det_state;
+ /* keep priv's existing 11h state */
+ if (pmpriv->intf_state_11h.is_11h_active)
+ mib_11h |= ENABLE_11H_MASK;
+
+ /* Send cmd to FW to enable/disable 11h function in firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11H_i, MNULL, &mib_11h);
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* updated state sent OR no change, thus no longer pending */
+ pmpriv->adapter->state_11h.master_radar_det_enable_pending = MFALSE;
+ pmpriv->adapter->state_11h.slave_radar_det_enable_pending = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Query 11h firmware enabled state.
+ *
+ * Return whether the firmware currently has 11h extensions enabled
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h has been activated in the firmware
+ * - MFALSE otherwise
+ *
+ * @sa wlan_11h_activate
+ */
+t_bool
+wlan_11h_is_active(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->intf_state_11h.is_11h_active);
+}
+
+/**
+ * @brief Enable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_tx_enable(mlan_private * priv)
+{
+ ENTER();
+ if (priv->intf_state_11h.tx_disabled) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_START_TX, MNULL);
+ priv->intf_state_11h.tx_disabled = MFALSE;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Disable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_tx_disable(mlan_private * priv)
+{
+ ENTER();
+ if (!priv->intf_state_11h.tx_disabled) {
+ priv->intf_state_11h.tx_disabled = MTRUE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_STOP_TX, MNULL);
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Enable or Disable the 11h extensions in the firmware
+ *
+ * @param priv Private driver information structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param flag Enable 11h if MTRUE, disable otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_activate(mlan_private * priv, t_void * pioctl_buf, t_bool flag)
+{
+ t_u32 enable = flag & ENABLE_11H_MASK;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* add bits for master/slave radar detect into enable. */
+ enable |= wlan_11h_get_current_radar_detect_flags(priv->adapter);
+
+ /*
+ * Send cmd to FW to enable/disable 11h function in firmware
+ */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11H_i, (t_void *) pioctl_buf, &enable);
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ /* Set boolean flag in driver 11h state */
+ priv->intf_state_11h.is_11h_active = flag;
+
+ PRINTM(MINFO, "11h: %s\n", flag ? "Activate" : "Deactivate");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_init(mlan_adapter * adapter)
+{
+ wlan_11h_device_state_t *pstate_11h = &adapter->state_11h;
+ IEEEtypes_Quiet_t *pquiet = &adapter->state_11h.quiet_ie;
+ wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &adapter->state_rdh;
+#ifdef DFS_TESTING_SUPPORT
+ wlan_dfs_testing_settings_t *pdfs_test = &adapter->dfs_test_params;
+#endif
+
+ ENTER();
+
+ /* Initialize 11H struct */
+ pstate_11h->usr_def_power_constraint = WLAN_11H_TPC_POWERCONSTRAINT;
+ pstate_11h->min_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MIN;
+ pstate_11h->max_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MAX;
+
+ pstate_11h->recvd_chanswann_event = MFALSE;
+ pstate_11h->master_radar_det_enable_pending = MFALSE;
+ pstate_11h->slave_radar_det_enable_pending = MFALSE;
+ pstate_11h->is_master_radar_det_active = MFALSE;
+ pstate_11h->is_slave_radar_det_active = MFALSE;
+
+ /* Initialize quiet_ie */
+ memset(adapter, pquiet, 0, sizeof(IEEEtypes_Quiet_t));
+ pquiet->element_id = QUIET;
+ pquiet->len = (sizeof(pquiet->quiet_count) + sizeof(pquiet->quiet_period)
+ + sizeof(pquiet->quiet_duration)
+ + sizeof(pquiet->quiet_offset));
+
+ /* Initialize DFS struct */
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_radar_found = MFALSE;
+ pstate_dfs->dfs_check_channel = 0;
+ pstate_dfs->dfs_report_time_sec = 0;
+ util_init_list((pmlan_linked_list) & pstate_dfs->dfs_ts_head);
+
+ /* Initialize RDH struct */
+ pstate_rdh->stage = RDH_OFF;
+ pstate_rdh->priv_list_count = 0;
+ pstate_rdh->priv_curr_idx = 0;
+ pstate_rdh->curr_channel = 0;
+ pstate_rdh->new_channel = 0;
+ pstate_rdh->uap_band_cfg = 0;
+ pstate_rdh->max_bcn_dtim_ms = 0;
+ memset(adapter, pstate_rdh->priv_list, 0, sizeof(pstate_rdh->priv_list));
+
+#ifdef DFS_TESTING_SUPPORT
+ /* Initialize DFS testing struct */
+ pdfs_test->user_cac_period_msec = 0;
+ pdfs_test->user_nop_period_sec = 0;
+ pdfs_test->no_channel_change_on_radar = MFALSE;
+ pdfs_test->fixed_new_channel_on_radar = 0;
+#endif
+
+ LEAVE();
+}
+
+/**
+ * @brief Cleanup for the 11h parameters that allocated memory, etc.
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_cleanup(mlan_adapter * adapter)
+{
+ wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
+ wlan_dfs_timestamp_t *pdfs_ts;
+
+ ENTER();
+
+ /* cleanup dfs_timestamp list */
+ pdfs_ts = (wlan_dfs_timestamp_t *) util_peek_list(adapter->pmoal_handle,
+ &pstate_dfs->dfs_ts_head,
+ MNULL, MNULL);
+ while (pdfs_ts) {
+ util_unlink_list(adapter->pmoal_handle, &pstate_dfs->dfs_ts_head,
+ (pmlan_linked_list) pdfs_ts, MNULL, MNULL);
+ adapter->callbacks.moal_mfree(adapter->pmoal_handle, (t_u8 *) pdfs_ts);
+
+ pdfs_ts = (wlan_dfs_timestamp_t *) util_peek_list(adapter->pmoal_handle,
+ &pstate_dfs->
+ dfs_ts_head, MNULL,
+ MNULL);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_priv_init(mlan_private * pmpriv)
+{
+ wlan_11h_interface_state_t *pistate_11h = &pmpriv->intf_state_11h;
+
+ ENTER();
+
+ pistate_11h->is_11h_enabled = MTRUE;
+ pistate_11h->is_11h_active = MFALSE;
+ pistate_11h->adhoc_auto_sel_chan = MTRUE;
+ pistate_11h->tx_disabled = MFALSE;
+
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and an A-Band channel start band preference
+ * configured in the driver, the start channel must be random in order
+ * to meet with
+ *
+ * @param priv Private driver information structure
+ *
+ * @return Starting channel
+ */
+t_u8
+wlan_11h_get_adhoc_start_channel(mlan_private * priv)
+{
+ t_u8 start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ t_u32 region;
+ t_u32 rand_entry;
+ region_chan_t *chn_tbl;
+ t_u8 rand_tries = 0;
+
+ ENTER();
+
+ /*
+ * Set start_chn to the Default. Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN)
+ ) {
+ /*
+ * Set default to the A Band default. Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM); region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band */
+ if (chn_tbl->valid
+ && chn_tbl->region == adapter->region_code
+ && chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random number and
+ * use it to pick an entry in the table between 0
+ * and the number of channels in the table (NumCFP).
+ */
+ do {
+ rand_entry =
+ wlan_11h_get_random_num(adapter) % chn_tbl->num_cfp;
+ start_chn = (t_u8) chn_tbl->pcfp[rand_entry].channel;
+ } while ((wlan_11h_is_channel_under_nop(adapter, start_chn)
+ ||
+ ((adapter->state_rdh.stage ==
+ RDH_GET_INFO_CHANNEL) &&
+ wlan_11h_radar_detect_required(priv, start_chn)))
+ && (++rand_tries < MAX_RANDOM_CHANNEL_RETRIES));
+ }
+ }
+ }
+ }
+
+ PRINTM(MINFO, "11h: %s: AdHoc Channel set to %u\n",
+ wlan_11h_is_enabled(priv) ? "Enabled" : "Disabled", start_chn);
+
+ LEAVE();
+ return start_chn;
+}
+
+/**
+ * @brief Check if the current region's regulations require the input channel
+ * to be scanned for radar.
+ *
+ * Based on statically defined requirements for sub-bands per regulatory
+ * agency requirements.
+ *
+ * Used in adhoc start to determine if channel availability check is required
+ *
+ * @param priv Private driver information structure
+ * @param channel Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ */
+/** @sa wlan_11h_issue_radar_detect
+ */
+t_bool
+wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel)
+{
+ t_bool required = MFALSE;
+
+ ENTER();
+
+ /*
+ * No checks for 11h or measurement code being enabled is placed here
+ * since regulatory requirements exist whether we support them or not.
+ */
+
+ required = wlan_get_cfp_radar_detect(priv, channel);
+
+ if (!priv->adapter->region_code)
+ PRINTM(MINFO, "11h: Radar detection in CFP code[BG:%#x, A:%#x] "
+ "is %srequired for channel %d\n",
+ priv->adapter->cfp_code_bg, priv->adapter->cfp_code_a,
+ (required ? "" : "not "), channel);
+ else
+ PRINTM(MINFO, "11h: Radar detection in region %#02x "
+ "is %srequired for channel %d\n",
+ priv->adapter->region_code, (required ? "" : "not "), channel);
+
+ if (required == MTRUE && priv->media_connected == MTRUE
+ && priv->curr_bss_params.bss_descriptor.channel == channel) {
+ required = MFALSE;
+
+ PRINTM(MINFO, "11h: Radar detection not required. "
+ "Already operating on the channel\n");
+ }
+
+ LEAVE();
+ return required;
+}
+
+/**
+ * @brief Perform a radar measurement if required on given channel
+ *
+ * Check to see if the provided channel requires a channel availability
+ * check (60 second radar detection measurement). If required, perform
+ * measurement, stalling calling thread until the measurement completes
+ * and then report result.
+ *
+ * Used when starting an adhoc or AP network.
+ *
+ * @param priv Private driver information structure
+ * @param pioctl_req Pointer to IOCTL request buffer
+ * @param channel Channel on which to perform radar measurement
+ *
+ * @return
+ * - MTRUE if radar measurement request was successfully issued
+ * - MFALSE if radar detection is not required
+ * - < 0 for error during radar detection (if performed)
+ *
+ * @sa wlan_11h_radar_detect_required
+ */
+t_s32
+wlan_11h_issue_radar_detect(mlan_private * priv,
+ pmlan_ioctl_req pioctl_req, t_u8 channel)
+{
+ t_s32 ret;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+
+ ENTER();
+
+ ret = wlan_11h_radar_detect_required(priv, channel);
+ if (ret) {
+ /* Prepare and issue CMD_CHAN_RPT_REQ. */
+ memset(priv->adapter, &chan_rpt_req, 0x00, sizeof(chan_rpt_req));
+
+ chan_rpt_req.chan_desc.startFreq = START_FREQ_11A_BAND;
+ chan_rpt_req.chan_desc.chanWidth = 0; // 1 for 40Mhz
+ chan_rpt_req.chan_desc.chanNum = channel;
+ chan_rpt_req.millisec_dwell_time =
+ WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION;
+#ifdef DFS_TESTING_SUPPORT
+ if (priv->adapter->dfs_test_params.user_cac_period_msec) {
+ PRINTM(MCMD_D, "dfs_testing - user CAC period=%d (msec)\n",
+ priv->adapter->dfs_test_params.user_cac_period_msec);
+ chan_rpt_req.millisec_dwell_time =
+ priv->adapter->dfs_test_params.user_cac_period_msec;
+ }
+#endif
+
+ PRINTM(MMSG, "11h: issuing DFS Radar check for channel=%d."
+ " Please wait for response...\n", channel);
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *) pioctl_req,
+ (t_void *) & chan_rpt_req);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Checks if a radar measurement was performed on channel,
+ * and if so, whether radar was detected on it.
+ *
+ * Used when starting an adhoc network.
+ *
+ * @param priv Private driver information structure
+ * @param chan Channel to check upon
+ *
+ * @return
+ * - MLAN_STATUS_SUCCESS if no radar on channel
+ * - MLAN_STATUS_FAILURE if radar was found on channel
+ * - (TBD??) MLAN_STATUS_PENDING if radar report NEEDS TO BE REISSUED
+ *
+ * @sa wlan_11h_issue_radar_detect
+ * @sa wlan_11h_process_start
+ */
+mlan_status
+wlan_11h_check_chan_report(mlan_private * priv, t_u8 chan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ /* check report we hold is valid or not */
+ priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
+ &sec, &usec);
+
+ PRINTM(MINFO, "11h: %s()\n", __FUNCTION__);
+ PRINTM(MINFO, "- sec_now=%d, sec_report=%d.\n",
+ sec, pstate_dfs->dfs_report_time_sec);
+ PRINTM(MINFO, "- rpt_channel=%d, rpt_radar=%d.\n",
+ pstate_dfs->dfs_check_channel, pstate_dfs->dfs_radar_found);
+
+ if ((!pstate_dfs->dfs_check_pending) &&
+ (chan == pstate_dfs->dfs_check_channel) &&
+ ((sec - pstate_dfs->dfs_report_time_sec) <
+ MAX_DFS_REPORT_USABLE_AGE_SEC)) {
+ /* valid and not out-dated, check if radar */
+ if (pstate_dfs->dfs_radar_found) {
+ PRINTM(MMSG, "Radar was detected on channel %d.\n", chan);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ // TODO: reissue report request if not pending.
+ // BUT HOW to make the code wait for it???
+ /* For now, just fail since we don't have the info. */
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Adhoc start command.
+ *
+ * Activate 11h functionality in the firmware if driver has is enabled
+ * for 11h (configured by the application via IOCTL).
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param channel Channel on which we are starting the IBSS
+ * @param p11h_bss_info Input/Output parameter: Pointer to the 11h BSS
+ * information for this network that we are establishing.
+ * 11h sensed flag set on output if warranted.
+ *
+ * @return
+ * - MLAN_STATUS_SUCCESS if 11h is disabled
+ * - Integer number of bytes appended to the TLV output buffer (ppbuffer)
+ * - < 0 for error (e.g. radar detected on channel)
+ */
+t_s32
+wlan_11h_process_start(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ mlan_adapter *adapter = priv->adapter;
+ t_s32 ret = MLAN_STATUS_SUCCESS;
+ t_bool is_dfs_chan = MFALSE;
+
+ ENTER();
+ if (wlan_11h_is_enabled(priv)
+ && ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN)
+ )
+ ) {
+ if (!wlan_11d_is_enabled(priv)) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+#ifdef STA_SUPPORT
+ wlan_11d_create_dnld_countryinfo(priv, adapter->adhoc_start_band);
+#endif
+ }
+
+ /* Activate 11h functions in firmware, turns on capability bit */
+ wlan_11h_activate(priv, MNULL, MTRUE);
+ pcap_info->spectrum_mgmt = MTRUE;
+
+ /* If using a DFS channel, enable radar detection. */
+ is_dfs_chan = wlan_11h_radar_detect_required(priv, channel);
+ if (is_dfs_chan) {
+ if (!wlan_11h_is_master_radar_det_active(priv))
+ wlan_11h_config_master_radar_det(priv, MTRUE);
+ }
+ wlan_11h_check_update_radar_det_state(priv);
+
+ /* Set flag indicating this BSS we are starting is using 11h */
+ p11h_bss_info->sensed_11h = MTRUE;
+
+ if (is_dfs_chan) {
+ /* check if this channel is under NOP */
+ if (wlan_11h_is_channel_under_nop(adapter, channel))
+ ret = MLAN_STATUS_FAILURE;
+ /* check last channel report, if this channel is free of radar */
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_check_chan_report(priv, channel);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel, MNULL);
+ else
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MNULL, MFALSE);
+ pcap_info->spectrum_mgmt = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Join command for
+ * both adhoc and infra networks
+ *
+ * The TLV command processing for a BSS join for either adhoc or
+ * infrastructure network is performed with this function. The
+ * capability bits are inspected for the IBSS flag and the appropriate
+ * local routines are called to setup the necessary TLVs.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network information for the BSS we are
+ * joining.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param band Band on which we are joining the BSS
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this
+ * network that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer), MLAN_STATUS_FAILURE (-1),
+ * or MLAN_STATUS_SUCCESS (0)
+ */
+t_s32
+wlan_11h_process_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u8 band,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ t_s32 ret = 0;
+
+ ENTER();
+
+ if (priv->media_connected == MTRUE) {
+ if (wlan_11h_is_active(priv) == p11h_bss_info->sensed_11h) {
+ /* Assume DFS parameters are the same for roaming as long as the
+ current & next APs have the same spectrum mgmt capability bit
+ setting */
+ ret = MLAN_STATUS_SUCCESS;
+
+ } else {
+ /* No support for roaming between DFS/non-DFS yet */
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+ }
+
+ if (p11h_bss_info->sensed_11h) {
+ if (!wlan_11d_is_enabled(priv)) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+#ifdef STA_SUPPORT
+ wlan_11d_parse_dnld_countryinfo(priv, priv->pattempted_bss_desc);
+#endif
+ }
+ /* Activate 11h functions in firmware, turns on capability bit */
+ wlan_11h_activate(priv, MNULL, MTRUE);
+ pcap_info->spectrum_mgmt = MTRUE;
+
+ /* If using a DFS channel, enable radar detection. */
+ if ((band & BAND_A) && wlan_11h_radar_detect_required(priv, channel)) {
+ if (!wlan_11h_is_slave_radar_det_active(priv))
+ wlan_11h_config_slave_radar_det(priv, MTRUE);
+ }
+ wlan_11h_check_update_radar_det_state(priv);
+
+ if (pcap_info->ibss) {
+ PRINTM(MINFO, "11h: Adhoc join: Sensed\n");
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
+ p11h_bss_info);
+ } else {
+ PRINTM(MINFO, "11h: Infra join: Sensed\n");
+ ret = wlan_11h_process_infra_join(priv, ppbuffer, band,
+ channel, p11h_bss_info);
+ }
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MNULL, MFALSE);
+ pcap_info->spectrum_mgmt = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ *
+ * @brief Prepare the HostCmd_DS_Command structure for an 11h command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ */
+/** - HostCmd_CMD_CHAN_REPORT_REQUEST
+ */
+/**
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer pass through with data necessary for a
+ * specific command type
+ */
+/** @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+/** @sa wlan_11h_cmd_tpc_request
+ * @sa wlan_11h_cmd_tpc_info
+ * @sa wlan_11h_cmd_chan_sw_ann
+ */
+/** @sa wlan_11h_cmd_chan_report_req
+ */
+mlan_status
+wlan_11h_cmd_process(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const t_void * pinfo_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ ret = wlan_11h_cmd_tpc_request(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_TPC_INFO:
+ ret = wlan_11h_cmd_tpc_info(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ ret = wlan_11h_cmd_chan_sw_ann(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_chan_rpt_req(priv, pcmd_ptr, pinfo_buf);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware if from an 11h command
+ *
+ * Use the Command field to determine if the command response being
+ * is for 11h. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ */
+/** - HostCmd_CMD_CHAN_REPORT_REQUEST
+ */
+/**
+ * @param priv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware
+ * command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_cmdresp_process(mlan_private * priv, const HostCmd_DS_COMMAND * resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ HEXDUMP("11h: TPC REQUEST Rsp:", (t_u8 *) resp, (t_u32) resp->size);
+ memcpy(priv->adapter, priv->adapter->curr_cmd->pdata_buf,
+ &resp->params.tpc_req, sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+ break;
+
+ case HostCmd_CMD_802_11_TPC_INFO:
+ HEXDUMP("11h: TPC INFO Rsp Data:", (t_u8 *) resp, (t_u32) resp->size);
+ break;
+
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ PRINTM(MINFO, "11h: Ret ChSwAnn: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ PRINTM(MINFO, "11h: Ret ChanRptReq. Set dfs_check_pending and wait"
+ " for EVENT_CHANNEL_REPORT.\n");
+ priv->adapter->state_dfs.dfs_check_pending = MTRUE;
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an element from a scan response, copy relevant info for 11h
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param p11h_bss_info Output parameter: Pointer to the 11h BSS information
+ * for the network that is being processed
+ * @param pelement Pointer to the current IE we are inspecting for 11h
+ * relevance
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_process_bss_elem(mlan_adapter * pmadapter,
+ wlan_11h_bss_info_t * p11h_bss_info,
+ const t_u8 * pelement)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 element_len = *((t_u8 *) pelement + 1);
+
+ ENTER();
+ switch (*pelement) {
+ case POWER_CONSTRAINT:
+ PRINTM(MINFO, "11h: Power Constraint IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->power_constraint, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_PowerConstraint_t)));
+ p11h_bss_info->power_constraint.len =
+ MIN(element_len, (sizeof(IEEEtypes_PowerConstraint_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case POWER_CAPABILITY:
+ PRINTM(MINFO, "11h: Power Capability IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->power_capability, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_PowerCapability_t)));
+ p11h_bss_info->power_capability.len =
+ MIN(element_len, (sizeof(IEEEtypes_PowerCapability_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case TPC_REPORT:
+ PRINTM(MINFO, "11h: Tpc Report IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->tpc_report, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_TPCReport_t)));
+ p11h_bss_info->tpc_report.len =
+ MIN(element_len, (sizeof(IEEEtypes_TPCReport_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case CHANNEL_SWITCH_ANN:
+ PRINTM(MINFO, "11h: Channel Switch Ann IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->chan_switch_ann, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_ChanSwitchAnn_t)));
+ p11h_bss_info->chan_switch_ann.len =
+ MIN(element_len, (sizeof(IEEEtypes_ChanSwitchAnn_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case QUIET:
+ PRINTM(MINFO, "11h: Quiet IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->quiet, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_Quiet_t)));
+ p11h_bss_info->quiet.len = MIN(element_len, (sizeof(IEEEtypes_Quiet_t)
+ -
+ sizeof
+ (IEEEtypes_Header_t)));
+ break;
+
+ case IBSS_DFS:
+ PRINTM(MINFO, "11h: Ibss Dfs IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->ibss_dfs, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_IBSS_DFS_t)));
+ p11h_bss_info->ibss_dfs.len =
+ MIN(element_len, (sizeof(IEEEtypes_IBSS_DFS_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ /*
+ * These elements are not in beacons/probe responses. Included here
+ * to cover set of enumerated 11h elements.
+ */
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for CHANNEL_SWITCH_ANN event
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status
+wlan_11h_handle_event_chanswann(mlan_private * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ priv->adapter->state_11h.recvd_chanswann_event = MTRUE;
+
+#ifdef STA_SUPPORT
+ /* do directed deauth. priv flag above will cause different reason code */
+ PRINTM(MINFO, "11h: handle_event_chanswann() - sending deauth\n");
+ ret = wlan_disconnect(priv, MNULL,
+ &priv->curr_bss_params.bss_descriptor.mac_address);
+
+ /* clear region table so next scan will be all passive */
+ PRINTM(MINFO, "11h: handle_event_chanswann() - clear region table\n");
+ wlan_11d_clear_parsedtable(priv);
+#endif
+
+ priv->adapter->state_11h.recvd_chanswann_event = MFALSE;
+ LEAVE();
+ return ret;
+}
+
+#ifdef DFS_TESTING_SUPPORT
+/**
+ * @brief 802.11h DFS Testing configuration
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ mlan_ds_11h_dfs_testing *dfs_test = MNULL;
+ wlan_dfs_testing_settings_t *pdfs_test_params = MNULL;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+ dfs_test = &ds_11hcfg->param.dfs_testing;
+ pdfs_test_params = &pmadapter->dfs_test_params;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ dfs_test->usr_cac_period_msec = pdfs_test_params->user_cac_period_msec;
+ dfs_test->usr_nop_period_sec = pdfs_test_params->user_nop_period_sec;
+ dfs_test->usr_no_chan_change =
+ pdfs_test_params->no_channel_change_on_radar;
+ dfs_test->usr_fixed_new_chan =
+ pdfs_test_params->fixed_new_channel_on_radar;
+ } else {
+ pdfs_test_params->user_cac_period_msec = dfs_test->usr_cac_period_msec;
+ pdfs_test_params->user_nop_period_sec = dfs_test->usr_nop_period_sec;
+ pdfs_test_params->no_channel_change_on_radar =
+ dfs_test->usr_no_chan_change;
+ pdfs_test_params->fixed_new_channel_on_radar =
+ dfs_test->usr_fixed_new_chan;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif // DFS_TESTING_SUPPORT
+
+/**
+ * @brief Check if channel is under NOP (Non-Occupancy Period)
+ * If so, the channel should not be used until the period expires.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param channel Channel number
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_11h_is_channel_under_nop(mlan_adapter * pmadapter, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pdfs_ts = MNULL;
+ t_u32 now_sec, now_usec;
+ t_bool ret = MFALSE;
+
+ ENTER();
+ pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
+
+ if (pdfs_ts && (pdfs_ts->channel == channel)
+ && (pdfs_ts->represents == DFS_TS_REPR_NOP_START)) {
+ /* found NOP_start timestamp entry on channel */
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &now_sec, &now_usec);
+#ifdef DFS_TESTING_SUPPORT
+ if (pmadapter->dfs_test_params.user_nop_period_sec) {
+ PRINTM(MCMD_D, "dfs_testing - user NOP period=%d (sec)\n",
+ pmadapter->dfs_test_params.user_nop_period_sec);
+ if ((now_sec - pdfs_ts->ts_sec) <=
+ pmadapter->dfs_test_params.user_nop_period_sec) {
+ ret = MTRUE;
+ }
+ } else
+#endif
+ {
+ if ((now_sec - pdfs_ts->ts_sec) <= WLAN_11H_NON_OCCUPANCY_PERIOD)
+ ret = MTRUE;
+ }
+
+ /* if entry is expired, remove it */
+ if (!ret)
+ wlan_11h_remove_dfs_timestamp(pmadapter, pdfs_ts);
+ else
+ PRINTM(MMSG, "11h: channel %d is under NOP - can't use.\n",
+ channel);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for CHANNEL_REPORT_RDY event
+ * This event will have the channel report data appended.
+ *
+ * @param priv Pointer to mlan_private
+ * @param pevent Pointer to mlan_event
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_handle_event_chanrpt_ready(mlan_private * priv, mlan_event * pevent)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_CHAN_RPT_RSP *pChanRptRsp;
+ MrvlIEtypes_Data_t *pTlv;
+ MeasRptBasicMap_t *pMeasRptBasic;
+ t_u8 *pBuffer;
+ t_s32 evtLen;
+ t_u16 tlvLen;
+ t_u32 sec, uSec;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+
+ ENTER();
+ pChanRptRsp = (HostCmd_DS_CHAN_RPT_RSP *) & pevent->event_buf;
+ DBG_HEXDUMP(MCMD_D, "11h: Event ChanRptReady (HostCmd_DS_CHAN_RPT_RSP)",
+ (t_u8 *) pChanRptRsp, wlan_le32_to_cpu(pevent->event_len));
+
+ if (wlan_le32_to_cpu(pChanRptRsp->cmd_result) == MLAN_CMD_RESULT_SUCCESS) {
+ pBuffer = (t_u8 *) & pChanRptRsp->tlv_buffer;
+ evtLen = wlan_le32_to_cpu(pevent->event_len);
+ evtLen -=
+ sizeof(HostCmd_DS_CHAN_RPT_RSP) - sizeof(pChanRptRsp->tlv_buffer);
+
+ while (evtLen >= sizeof(MrvlIEtypesHeader_t)) {
+ pTlv = (MrvlIEtypes_Data_t *) pBuffer;
+ tlvLen = wlan_le16_to_cpu(pTlv->header.len);
+
+ switch (wlan_le16_to_cpu(pTlv->header.type)) {
+ case TLV_TYPE_CHANRPT_11H_BASIC:
+ pMeasRptBasic = (MeasRptBasicMap_t *) & pTlv->data;
+ if (pMeasRptBasic->radar) {
+ pstate_dfs->dfs_radar_found = MTRUE;
+ PRINTM(MMSG, "RADAR Detected on channel %d!\n",
+ pstate_dfs->dfs_check_channel);
+ /* add channel to NOP list */
+ wlan_11h_add_dfs_timestamp(priv->adapter,
+ DFS_TS_REPR_NOP_START,
+ pstate_dfs->dfs_check_channel);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pBuffer += (tlvLen + sizeof(pTlv->header));
+ evtLen -= (tlvLen + sizeof(pTlv->header));
+ evtLen = (evtLen > 0) ? evtLen : 0;
+ }
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* Update DFS structure. */
+ priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
+ &sec, &uSec);
+ pstate_dfs->dfs_report_time_sec = sec;
+ pstate_dfs->dfs_check_pending = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check if RADAR_DETECTED handling is blocking data tx
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_11h_radar_detected_tx_blocked(mlan_adapter * pmadapter)
+{
+ switch (pmadapter->state_rdh.stage) {
+ case RDH_OFF:
+ case RDH_CHK_INTFS:
+ case RDH_STOP_TRAFFIC:
+ return MFALSE;
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Callback for RADAR_DETECTED event driver handling
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_radar_detected_callback(t_void * priv)
+{
+ mlan_status ret;
+ ENTER();
+ ret = wlan_11h_radar_detected_handling(((mlan_private *) (priv))->adapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for RADAR_DETECTED event
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status
+wlan_11h_radar_detected_handling(mlan_adapter * pmadapter)
+{
+#ifdef DEBUG_LEVEL1
+ const char *RDH_stage_str[] = {
+ "RDH_OFF",
+ "RDH_CHK_INTFS",
+ "RDH_STOP_TRAFFIC",
+ "RDH_GET_INFO_CHANNEL",
+ "RDH_GET_INFO_BEACON_DTIM",
+ "RDH_SET_CUSTOM_IE",
+ "RDH_REM_CUSTOM_IE",
+ "RDH_STOP_INTFS",
+ "RDH_SET_NEW_CHANNEL",
+ "RDH_RESTART_INTFS",
+ "RDH_RESTART_TRAFFIC"
+ };
+#endif
+
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = MNULL;
+ t_u32 i;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &pmadapter->state_rdh;
+
+ ENTER();
+
+ switch (pstate_rdh->stage) {
+ case RDH_CHK_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+
+ /* get active interfaces */
+ memset(pmadapter, pstate_rdh->priv_list, 0x00,
+ sizeof(pstate_rdh->priv_list));
+ pstate_rdh->priv_list_count = wlan_get_privs_by_cond(pmadapter,
+ wlan_is_intf_active,
+ pstate_rdh->
+ priv_list);
+ PRINTM(MCMD_D, "%s(): priv_list_count = %d\n", __FUNCTION__,
+ pstate_rdh->priv_list_count);
+ for (i = 0; i < pstate_rdh->priv_list_count; i++)
+ PRINTM(MINFO, "%s(): priv_list[%d] = %p\n",
+ __FUNCTION__, i, pstate_rdh->priv_list[i]);
+
+ if (pstate_rdh->priv_list_count == 0) {
+ /* no interfaces active... nothing to do */
+ PRINTM(MMSG, "11h: Radar Detected - no active priv's,"
+ " skip event handling.\n");
+ pstate_rdh->stage = RDH_OFF;
+ PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+ break; // EXIT CASE
+ }
+ // else: start handling
+ pstate_rdh->curr_channel = 0;
+ pstate_rdh->new_channel = 0;
+ pstate_rdh->uap_band_cfg = 0;
+ pstate_rdh->max_bcn_dtim_ms = 0;
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_STOP_TRAFFIC;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_STOP_TRAFFIC:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+
+ PRINTM(MMSG, "11h: Radar Detected - stopping host tx traffic.\n");
+ for (i = 0; i < pstate_rdh->priv_list_count; i++) {
+ wlan_11h_tx_disable(pstate_rdh->priv_list[i]);
+ }
+
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_GET_INFO_CHANNEL;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_GET_INFO_CHANNEL:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* here, prefer STA info over UAP info - one less CMD to send */
+ if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ if (wlan_only_uap_priv_in_list(pstate_rdh->priv_list,
+ pstate_rdh->priv_list_count)) {
+#ifdef UAP_SUPPORT
+ /* Assume all UAPs on same channel, use first UAP */
+ pmpriv = pstate_rdh->priv_list[0];
+ pstate_rdh->priv_curr_idx = 0;
+ /* send cmd to get first UAP's info */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback
+ = wlan_11h_radar_detected_callback;
+ ret = wlan_uap_get_channel(pmpriv);
+ break; // EXIT CASE
+#endif
+ } else {
+ /* Assume all STAs on same channel, find first STA */
+ MASSERT(pstate_rdh->priv_list_count > 0);
+ for (i = 0; i < pstate_rdh->priv_list_count; i++) {
+ pmpriv = pstate_rdh->priv_list[i];
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ break;
+ }
+ /* STA info kept in driver, just copy */
+ pstate_rdh->curr_channel =
+ pmpriv->curr_bss_params.bss_descriptor.channel;
+ }
+ }
+#ifdef UAP_SUPPORT
+ else if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count) {
+ /* repeat entry: UAP return with info */
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+ pstate_rdh->curr_channel = pmpriv->uap_state_chan_cb.channel;
+ pstate_rdh->uap_band_cfg = pmpriv->uap_state_chan_cb.band_config;
+ PRINTM(MCMD_D, "%s(): uap_band_cfg=0x%02x\n",
+ __FUNCTION__, pstate_rdh->uap_band_cfg);
+ }
+#endif
+
+ /* add channel to NOP list */
+ wlan_11h_add_dfs_timestamp(pmadapter, DFS_TS_REPR_NOP_START,
+ pstate_rdh->curr_channel);
+
+ /* choose new channel (!= curr channel) and move on */
+ i = 0;
+ do {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ pstate_rdh->new_channel = wlan_11h_get_uap_start_channel(pmpriv,
+ pmpriv->
+ uap_state_chan_cb.
+ band_config);
+ else
+#endif
+ pstate_rdh->new_channel =
+ wlan_11h_get_adhoc_start_channel(pmpriv);
+ } while ((pstate_rdh->new_channel == pstate_rdh->curr_channel) && (++i < MAX_RANDOM_CHANNEL_RETRIES)); /* avoid
+ deadloop
+ */
+ if (i >= MAX_RANDOM_CHANNEL_RETRIES) /* report error */
+ PRINTM(MERROR, "%s(): ERROR - could not choose new_chan"
+ " (!= curr_chan) !!\n", __FUNCTION__);
+
+#ifdef DFS_TESTING_SUPPORT
+ if (pmadapter->dfs_test_params.fixed_new_channel_on_radar) {
+ PRINTM(MCMD_D, "dfs_testing - user fixed new_chan=%d\n",
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar);
+ pstate_rdh->new_channel =
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar;
+ }
+#endif
+ PRINTM(MCMD_D, "%s(): curr_chan=%d, new_chan=%d\n",
+ __FUNCTION__, pstate_rdh->curr_channel, pstate_rdh->new_channel);
+
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_GET_INFO_BEACON_DTIM;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_GET_INFO_BEACON_DTIM:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+#ifdef UAP_SUPPORT
+ /* check all intfs in this stage to find longest period */
+ /* UAP intf callback returning with info */
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count) {
+ t_u16 bcn_dtim_msec;
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+ PRINTM(MCMD_D, "%s(): uap.bcn_pd=%d, uap.dtim_pd=%d\n",
+ __FUNCTION__, pmpriv->uap_state_chan_cb.beacon_period,
+ pmpriv->uap_state_chan_cb.dtim_period);
+ bcn_dtim_msec = (pmpriv->uap_state_chan_cb.beacon_period
+ * pmpriv->uap_state_chan_cb.dtim_period);
+ if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
+ pstate_rdh->max_bcn_dtim_ms = bcn_dtim_msec;
+ }
+#endif
+
+ /* check next intf */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback
+ = wlan_11h_radar_detected_callback;
+ ret = wlan_uap_get_beacon_dtim(pmpriv);
+ break; // leads to exit case
+ } else
+#endif
+ { /* get STA info from driver and compare here */
+ t_u16 bcn_pd_msec = 100;
+ t_u16 dtim_pd_msec = 1;
+ t_u16 bcn_dtim_msec;
+
+ if (wlan_11h_is_dfs_master(pmpriv)) { /* adhoc creator */
+ bcn_pd_msec = pmpriv->beacon_period;
+ } else {
+ bcn_pd_msec =
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period;
+ // if (priv->bss_mode != MLAN_BSS_MODE_IBSS)
+ /* TODO: mlan_scan.c needs to parse TLV 0x05 (TIM) for
+ dtim_period */
+ }
+ PRINTM(MCMD_D, "%s(): sta.bcn_pd=%d, sta.dtim_pd=%d\n",
+ __FUNCTION__, bcn_pd_msec, dtim_pd_msec);
+ bcn_dtim_msec = (bcn_pd_msec * dtim_pd_msec);
+ if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
+ pstate_rdh->max_bcn_dtim_ms = bcn_dtim_msec;
+ }
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE (for UAP)
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_SET_CUSTOM_IE;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_SET_CUSTOM_IE:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* add CHAN_SW IE - firmware will accept on any interface, and apply to
+ all */
+ if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+
+ ret =
+ wlan_11h_prepare_custom_ie_chansw(pmadapter, &pioctl_req,
+ MTRUE);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Error in preparng CHAN_SW IE.\n",
+ __FUNCTION__);
+ break; // EXIT CASE
+ }
+
+ PRINTM(MMSG,
+ "11h: Radar Detected - adding CHAN_SW IE to interfaces.\n");
+ pmpriv = pstate_rdh->priv_list[0];
+ pstate_rdh->priv_curr_idx = 0;
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
+ __FUNCTION__, pmpriv, pmpriv->bss_index);
+ // TODO: how to handle this error case?? ignore & continue?
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pioctl_req);
+ break; // EXIT CASE
+ }
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_REM_CUSTOM_IE;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_REM_CUSTOM_IE:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* remove CHAN_SW IE - firmware will accept on any interface, and apply
+ to all */
+ if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+
+ /* first entry to this stage, do delay DFS requires a minimum of 5
+ chances for clients to hear this IE. Use delay: 5 beacons <=
+ (BCN_DTIM_MSEC*5) <= 3 seconds). */
+ t_u16 delay_ms = MAX(MIN_RDH_CHAN_SW_IE_PERIOD_MSEC,
+ MIN((5 * pstate_rdh->max_bcn_dtim_ms),
+ MAX_RDH_CHAN_SW_IE_PERIOD_MSEC));
+ PRINTM(MMSG, "11h: Radar Detected - delay %d ms for FW to"
+ " broadcast CHAN_SW IE.\n", delay_ms);
+ wlan_mdelay(pmadapter, delay_ms);
+ PRINTM(MMSG, "11h: Radar Detected - delay over, removing"
+ " CHAN_SW IE from interfaces.\n");
+
+ ret =
+ wlan_11h_prepare_custom_ie_chansw(pmadapter, &pioctl_req,
+ MFALSE);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Error in preparng CHAN_SW IE.\n",
+ __FUNCTION__);
+ break; // EXIT CASE
+ }
+
+ pmpriv = pstate_rdh->priv_list[0];
+ pstate_rdh->priv_curr_idx = 0;
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
+ __FUNCTION__, pmpriv, pmpriv->bss_index);
+ // TODO: how to handle this error case?? ignore & continue?
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pioctl_req);
+ break; // EXIT CASE
+ }
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_STOP_INTFS;
+#ifdef DFS_TESTING_SUPPORT
+ if (pmadapter->dfs_test_params.no_channel_change_on_radar) {
+ PRINTM(MCMD_D, "dfs_testing - no channel change on radar."
+ " Also skip stop/restart interface stages.\n",
+ pmadapter->dfs_test_params.no_channel_change_on_radar);
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_TRAFFIC;
+ goto rdh_restart_traffic; // skip several stages
+ }
+#endif
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_STOP_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* issues one cmd (DEAUTH/ADHOC_STOP/BSS_STOP) to each intf */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ break; // leads to exit case
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ /* Save ad-hoc creator state before stop clears it */
+ pmpriv->adhoc_state_prev = pmpriv->adhoc_state;
+ }
+ if (pmpriv->media_connected == MTRUE) {
+ wlan_disconnect(pmpriv, MNULL, MNULL);
+ break; // leads to exit case
+ }
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_SET_NEW_CHANNEL;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_SET_NEW_CHANNEL:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* only set new channel for UAP intfs */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback
+ = wlan_11h_radar_detected_callback;
+ pstate_rdh->uap_band_cfg |= UAP_BAND_CONFIG_5GHZ; /* DFS
+ only
+ in
+ 5GHz
+ */
+ ret = wlan_uap_set_channel(pmpriv, pstate_rdh->uap_band_cfg,
+ pstate_rdh->new_channel);
+ break; // leads to exit case
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE (for UAP)
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_INTFS;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_RESTART_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* can only restart master intfs */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pstate_rdh->new_channel)) {
+ /* Radar detection is required for this channel, make sure
+ 11h is activated in the firmware */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+ }
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ break; // leads to exit case
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ /* Check previous state to find former Ad-hoc creator
+ interface. Set new state to Starting, so it'll be seen as a
+ DFS master. */
+ if (pmpriv->adhoc_state_prev == ADHOC_STARTED) {
+ pmpriv->adhoc_state = ADHOC_STARTING;
+ pmpriv->adhoc_state_prev = ADHOC_IDLE;
+ }
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ /* set new adhoc channel here */
+ pmpriv->adhoc_channel = pstate_rdh->new_channel;
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pstate_rdh->
+ new_channel)) {
+ /* Radar detection is required for this channel, make
+ sure 11h is activated in the firmware */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+ }
+ ret =
+ wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->adhoc_last_start_ssid);
+ break; // leads to exit case
+ }
+
+ /* NOTE: DON'T reconnect slave STA intfs - infra/adhoc_joiner
+ Do we want to return to same AP/network (on radar channel)?
+ If want to connect back, depend on either: 1. driver's
+ reassoc thread 2. wpa_supplicant, or other user-space app */
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE (for UAP)
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_TRAFFIC;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_RESTART_TRAFFIC:
+#ifdef DFS_TESTING_SUPPORT
+ rdh_restart_traffic:
+#endif
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+
+ /* continue traffic for reactivated interfaces */
+ PRINTM(MMSG, "11h: Radar Detected - restarting host tx traffic.\n");
+ for (i = 0; i < pstate_rdh->priv_list_count; i++) {
+ wlan_11h_tx_enable(pstate_rdh->priv_list[i]);
+ }
+
+ pstate_rdh->stage = RDH_OFF; /* DONE! */
+ PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+ break;
+
+ default:
+ pstate_rdh->stage = RDH_OFF; /* cancel RDH to unblock Tx packets */
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief DFS Event Preprocessing.
+ * Operates directly on pmadapter variables.
+ *
+ * 1. EVENT_RADAR_DETECTED comes from firmware without specific
+ * bss_num/bss_type. Find it an appropriate interface and
+ * update event_cause field in event_buf.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS (update successful)
+ * or MLAN_STATUS_FAILURE (no change)
+ */
+mlan_status
+wlan_11h_dfs_event_preprocessing(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = MNULL;
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+
+ ENTER();
+ switch (pmadapter->event_cause & EVENT_ID_MASK) {
+ case EVENT_RADAR_DETECTED:
+ /* find active intf: prefer dfs_master over dfs_slave */
+ if (wlan_get_privs_by_two_cond(pmadapter,
+ wlan_11h_is_master_active_on_dfs_chan,
+ wlan_11h_is_dfs_master,
+ MTRUE, priv_list)) {
+ pmpriv = priv_list[0];
+ PRINTM(MINFO, "%s: found dfs_master priv=%p\n",
+ __FUNCTION__, pmpriv);
+ } else if (wlan_get_privs_by_two_cond(pmadapter,
+ wlan_11h_is_slave_active_on_dfs_chan,
+ wlan_11h_is_dfs_slave,
+ MTRUE, priv_list)) {
+ pmpriv = priv_list[0];
+ PRINTM(MINFO, "%s: found dfs_slave priv=%p\n",
+ __FUNCTION__, pmpriv);
+ }
+
+ /* update event_cause if we found an appropriate priv */
+ if (pmpriv) {
+ pmlan_buffer pmevbuf = pmadapter->pmlan_buffer_event;
+ t_u32 new_event_cause = pmadapter->event_cause & EVENT_ID_MASK;
+ new_event_cause |= ((GET_BSS_NUM(pmpriv) & 0xff) << 16) |
+ ((pmpriv->bss_type & 0xff) << 24);
+ PRINTM(MINFO, "%s: priv - bss_num=%d, bss_type=%d\n",
+ __FUNCTION__, GET_BSS_NUM(pmpriv), pmpriv->bss_type);
+ memcpy(pmadapter, pmevbuf->pbuf + pmevbuf->data_offset,
+ &new_event_cause, sizeof(new_event_cause));
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief try to switch to a non-dfs channel
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @param chan pointer to channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status
+wlan_11h_switch_non_dfs_chan(mlan_private * priv, t_u8 * chan)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u32 i;
+ t_u32 rand_entry;
+ t_u8 def_chan;
+ t_u8 rand_tries = 0;
+ region_chan_t *chn_tbl = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ /* get the channel table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (pmadapter->region_channel[i].band == BAND_A
+ && pmadapter->region_channel[i].valid) {
+ chn_tbl = &pmadapter->region_channel[i];
+ break;
+ }
+ }
+
+ if (!chn_tbl || !chn_tbl->pcfp) {
+ goto done;
+ }
+
+ do {
+ rand_entry = wlan_11h_get_random_num(pmadapter) % chn_tbl->num_cfp;
+ def_chan = (t_u8) chn_tbl->pcfp[rand_entry].channel;
+ rand_tries++;
+ } while ((wlan_11h_is_channel_under_nop(pmadapter, def_chan) ||
+ chn_tbl->pcfp[rand_entry].passive_scan_or_radar_detect == MTRUE)
+ && (rand_tries < MAX_SWITCH_CHANNEL_RETRIES));
+
+ /* meet max retries, use the lowest non-dfs channel */
+ if (rand_tries == MAX_SWITCH_CHANNEL_RETRIES) {
+ for (i = 0; i < chn_tbl->num_cfp; i++) {
+ if (chn_tbl->pcfp[i].passive_scan_or_radar_detect == MFALSE &&
+ !wlan_11h_is_channel_under_nop(pmadapter,
+ (t_u8) chn_tbl->pcfp[i].
+ channel)) {
+ def_chan = (t_u8) chn_tbl->pcfp[i].channel;
+ break;
+ }
+ }
+ if (i == chn_tbl->num_cfp) {
+ goto done;
+ }
+ }
+
+ *chan = def_chan;
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11h.h b/drivers/net/wireless/sd8797/mlan/mlan_11h.h
new file mode 100644
index 00000000..cfa7fb9
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11h.h
@@ -0,0 +1,158 @@
+/** @file mlan_11h.h
+ *
+ * @brief This header file contains data structures and
+ * function declarations of 802.11h
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial creation
+*************************************************************/
+
+#ifndef _MLAN_11H_
+#define _MLAN_11H_
+
+/** 11H OID bitmasks */
+#define ENABLE_11H_MASK MBIT(0)
+#define MASTER_RADAR_DET_MASK MBIT(1)
+#define SLAVE_RADAR_DET_MASK MBIT(2)
+
+/** DFS Master Radar Detect global enable */
+#define DFS_MASTER_RADAR_DETECT_EN (MTRUE)
+/** DFS Slave Radar Detect global enable */
+#define DFS_SLAVE_RADAR_DETECT_EN (MFALSE)
+
+/**
+ * 11H APIs
+ */
+
+/* Is master radar detection enabled in firmware? */
+extern t_bool wlan_11h_is_master_radar_det_active(mlan_private * priv);
+
+/** Configure master radar detection. Need call wlan_11h_check_update_radar_det_state() after. */
+extern mlan_status wlan_11h_config_master_radar_det(mlan_private * priv,
+ t_bool enable);
+
+/** Configure slave radar detection. Need call wlan_11h_check_update_radar_det_state() after. */
+extern mlan_status wlan_11h_config_slave_radar_det(mlan_private * priv,
+ t_bool enable);
+
+/** Checks all interfaces and updates radar detect flags if necessary */
+extern mlan_status wlan_11h_check_update_radar_det_state(mlan_private * pmpriv);
+
+/** Return 1 if 11h is active in the firmware, 0 if it is inactive */
+extern t_bool wlan_11h_is_active(mlan_private * priv);
+
+/** Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_enable(mlan_private * priv);
+
+/** Disable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_disable(mlan_private * priv);
+
+/** Activate 11h extensions in the firmware */
+extern mlan_status wlan_11h_activate(mlan_private * priv, t_void * pioctl_buf,
+ t_bool flag);
+
+/** Initialize the 11h device structure */
+extern void wlan_11h_init(mlan_adapter * pmadapter);
+
+/** Cleanup for the 11h device structure */
+extern void wlan_11h_cleanup(mlan_adapter * pmadapter);
+
+/** Initialize the 11h interface structure */
+extern void wlan_11h_priv_init(mlan_private * pmpriv);
+
+/** Get an initial random channel to start an adhoc network on */
+extern t_u8 wlan_11h_get_adhoc_start_channel(mlan_private * priv);
+
+/** Check if radar detection is required on the specified channel */
+extern t_bool wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel);
+
+/** Perform a standard availibility check on the specified channel */
+extern t_s32 wlan_11h_issue_radar_detect(mlan_private * priv,
+ pmlan_ioctl_req pioctl_req,
+ t_u8 channel);
+
+/** Check previously issued radar report for a channel */
+extern mlan_status wlan_11h_check_chan_report(mlan_private * priv, t_u8 chan);
+
+/** Add any 11h TLVs necessary to complete an adhoc start command */
+extern t_s32 wlan_11h_process_start(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel,
+ wlan_11h_bss_info_t * p11h_bss_info);
+
+/** Add any 11h TLVs necessary to complete a join command (adhoc or infra) */
+extern t_s32 wlan_11h_process_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u8 band,
+ t_u32 channel,
+ wlan_11h_bss_info_t * p11h_bss_info);
+
+/** Complete the firmware command preparation for an 11h command function */
+extern mlan_status wlan_11h_cmd_process(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf);
+
+/** Process the response of an 11h firmware command */
+extern mlan_status wlan_11h_cmdresp_process(mlan_private * priv,
+ const HostCmd_DS_COMMAND * resp);
+
+/** Receive IEs from scan processing and record any needed info for 11h */
+extern mlan_status wlan_11h_process_bss_elem(mlan_adapter * pmadapter,
+ wlan_11h_bss_info_t *
+ p11h_bss_info,
+ const t_u8 * pelement);
+
+/** Handler for EVENT_CHANNEL_SWITCH_ANN */
+extern mlan_status wlan_11h_handle_event_chanswann(mlan_private * priv);
+
+/** Handler for EVENT_CHANNEL_REPORT_RDY */
+extern mlan_status wlan_11h_handle_event_chanrpt_ready(mlan_private * priv,
+ mlan_event * pevent);
+
+#ifdef DFS_TESTING_SUPPORT
+/** Handler for DFS_TESTING IOCTL */
+extern mlan_status wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+
+/** Check if channel is under a NOP duration (should not be used) */
+extern t_bool wlan_11h_is_channel_under_nop(mlan_adapter * pmadapter,
+ t_u8 channel);
+
+/** Check if RADAR_DETECTED handling is blocking data tx */
+extern t_bool wlan_11h_radar_detected_tx_blocked(mlan_adapter * pmadapter);
+
+/** Callback for RADAR_DETECTED (for UAP cmdresp) */
+extern mlan_status wlan_11h_radar_detected_callback(t_void * priv);
+
+/** Handler for RADAR_DETECTED */
+extern mlan_status wlan_11h_radar_detected_handling(mlan_adapter * pmadapter);
+
+/** DFS Event pre-processing */
+extern mlan_status wlan_11h_dfs_event_preprocessing(mlan_adapter * pmadapter);
+
+/** DFS switch to non-DFS channel */
+extern mlan_status wlan_11h_switch_non_dfs_chan(mlan_private * priv,
+ t_u8 * chan);
+
+#endif /*_MLAN_11H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n.c b/drivers/net/wireless/sd8797/mlan/mlan_11n.c
new file mode 100644
index 00000000..5e78748
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n.c
@@ -0,0 +1,1936 @@
+/** @file mlan_11n.c
+ *
+ * @brief This file contains functions for 11n handling.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ *
+ * @brief set/get max tx buf size
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_max_tx_buf_size(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ cfg->param.tx_buf_size = (t_u32) pmadapter->max_tx_buf_size;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get htcapinfo configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (((cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP) &
+ pmpriv->adapter->hw_dot_11n_dev_cap)
+ != (cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
+ pmadapter->usr_dot_11n_dev_cap_bg = cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "Set: UsrDot11nCap for 2.4GHz 0x%x\n",
+ pmadapter->usr_dot_11n_dev_cap_bg);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
+ pmadapter->usr_dot_11n_dev_cap_a = cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "Set: UsrDot11nCap for 5GHz 0x%x\n",
+ pmadapter->usr_dot_11n_dev_cap_a);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BOTH) {
+ pmadapter->usr_dot_11n_dev_cap_bg = cfg->param.htcap_cfg.htcap;
+ pmadapter->usr_dot_11n_dev_cap_a = cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "Set: UsrDot11nCap for 2.4GHz and 5GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ }
+ } else {
+ /* Hardware 11N device capability required */
+ if (cfg->param.htcap_cfg.hw_cap_req)
+ cfg->param.htcap_cfg.htcap = pmadapter->hw_dot_11n_dev_cap;
+ else {
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
+ cfg->param.htcap_cfg.htcap = pmadapter->usr_dot_11n_dev_cap_bg;
+ PRINTM(MINFO, "Get: UsrDot11nCap for 2.4GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
+ cfg->param.htcap_cfg.htcap = pmadapter->usr_dot_11n_dev_cap_a;
+ PRINTM(MINFO, "Get: UsrDot11nCap for 5GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable AMSDU AGGR CTRL
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_amsdu_aggr_ctrl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_AMSDU_AGGR_CTRL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.amsdu_aggr_ctrl);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get 11n configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_11N_CFG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.tx_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get TX beamforming capabilities
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_11n_ioctl_tx_bf_cap(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ pmpriv->tx_bf_cap = cfg->param.tx_bf_cap;
+ else
+ cfg->param.tx_bf_cap = pmpriv->tx_bf_cap;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get TX beamforming configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_tx_bf_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_BF_CFG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.tx_bf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_stream_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.stream_cfg = pmadapter->usr_dev_mcs_support;
+ } else if (pioctl_req->action == MLAN_ACT_SET) {
+ switch (cfg->param.stream_cfg) {
+ case HT_STREAM_MODE_2X2:
+ if (pmadapter->hw_dev_mcs_support == HT_STREAM_MODE_1X1) {
+ PRINTM(MERROR, "HW does not support this mode\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else
+ pmadapter->usr_dev_mcs_support = cfg->param.stream_cfg;
+ break;
+ case HT_STREAM_MODE_1X1:
+ pmadapter->usr_dev_mcs_support = cfg->param.stream_cfg;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid stream mode\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will resend addba request to all
+ * the peer in the TxBAStreamTbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+static void
+wlan_11n_update_addba_request(mlan_private * priv)
+{
+
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ wlan_send_addba(priv, ptx_tbl->tid, ptx_tbl->ra);
+ ptx_tbl = ptx_tbl->pnext;
+ }
+ /* Signal MOAL to trigger mlan_main_process */
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Set/get addba parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_11n_ioctl_addba_param(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u32 timeout;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.addba_param.timeout = pmpriv->add_ba_param.timeout;
+ cfg->param.addba_param.txwinsize = pmpriv->add_ba_param.tx_win_size;
+ cfg->param.addba_param.rxwinsize = pmpriv->add_ba_param.rx_win_size;
+ cfg->param.addba_param.txamsdu = pmpriv->add_ba_param.tx_amsdu;
+ cfg->param.addba_param.rxamsdu = pmpriv->add_ba_param.rx_amsdu;
+ } else {
+ timeout = pmpriv->add_ba_param.timeout;
+ pmpriv->add_ba_param.timeout = cfg->param.addba_param.timeout;
+ pmpriv->add_ba_param.tx_win_size = cfg->param.addba_param.txwinsize;
+ pmpriv->add_ba_param.rx_win_size = cfg->param.addba_param.rxwinsize;
+ pmpriv->add_ba_param.tx_amsdu = cfg->param.addba_param.txamsdu;
+ pmpriv->add_ba_param.rx_amsdu = cfg->param.addba_param.rxamsdu;
+ if (timeout != pmpriv->add_ba_param.timeout) {
+ wlan_11n_update_addba_request(pmpriv);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get addba reject set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_addba_reject(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ PRINTM(MINFO, "Get Addba reject\n");
+ memcpy(pmadapter, cfg->param.addba_reject, pmpriv->addba_reject,
+ MAX_NUM_TID);
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Can not set aggr priority table in connected"
+ " state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if (cfg->param.addba_reject[i] > ADDBA_RSP_STATUS_REJECT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->addba_reject[i] = cfg->param.addba_reject[i];
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get aggr_prio_tbl
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_aggr_prio_tbl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg->param.aggr_prio_tbl.ampdu[i] =
+ pmpriv->aggr_prio_tbl[i].ampdu_user;
+ cfg->param.aggr_prio_tbl.amsdu[i] = pmpriv->aggr_prio_tbl[i].amsdu;
+ }
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Can not set aggr priority table in connected"
+ " state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if ((cfg->param.aggr_prio_tbl.ampdu[i] > HIGH_PRIO_TID) &&
+ (cfg->param.aggr_prio_tbl.ampdu[i] != BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->aggr_prio_tbl[i].ampdu_ap =
+ pmpriv->aggr_prio_tbl[i].ampdu_user =
+ cfg->param.aggr_prio_tbl.ampdu[i];
+
+ /* For AMSDU */
+ if ((cfg->param.aggr_prio_tbl.amsdu[i] > HIGH_PRIO_TID &&
+ cfg->param.aggr_prio_tbl.amsdu[i] != BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ } else {
+ pmpriv->aggr_prio_tbl[i].amsdu =
+ cfg->param.aggr_prio_tbl.amsdu[i];
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get supported MCS set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_supported_mcs_set(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ int rx_mcs_supp;
+ t_u8 mcs_set[NUM_MCS_FIELD];
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Set operation is not supported\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rx_mcs_supp = GET_RXMCSSUPP(pmadapter->usr_dev_mcs_support);
+ /* Set MCS for 1x1/2x2 */
+ memset(pmadapter, (t_u8 *) mcs_set, 0xff, rx_mcs_supp);
+ /* Clear all the other values */
+ memset(pmadapter, (t_u8 *) & mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ if (ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap_bg)
+ || ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap_a)
+ )
+ SETHT_MCS32(mcs_set);
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ memcpy(pmadapter, cfg->param.supported_mcs_set, mcs_set, NUM_MCS_FIELD);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the given pointer is valid entry of
+ * Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptxtblptr Pointer to tx ba stream entry
+ *
+ * @return MTRUE or MFALSE
+ */
+static int
+wlan_is_txbastreamptr_valid(mlan_private * priv, TxBAStreamTbl * ptxtblptr)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr, MNULL,
+ MNULL))) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl == ptxtblptr) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will return the pointer to a entry in BA Stream
+ * table which matches the ba_status requested
+ *
+ * @param priv A pointer to mlan_private
+ * @param ba_status Current status of the BA stream
+ *
+ * @return A pointer to first entry matching status in BA stream
+ * NULL if not found
+ */
+static TxBAStreamTbl *
+wlan_11n_get_txbastream_status(mlan_private * priv, baStatus_e ba_status)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl->ba_status == ba_status) {
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function fills the cap info
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+static void
+wlan_fill_cap_info(mlan_private * priv,
+ MrvlIETypes_HTCap_t * pht_cap, t_u8 bands)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
+
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
+ SETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_GREENFIELD(usr_dot_11n_dev_cap))
+ SETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_SHORTGI20(usr_dot_11n_dev_cap))
+ SETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_SHORTGI40(usr_dot_11n_dev_cap))
+ SETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_RXSTBC(usr_dot_11n_dev_cap))
+ SETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info, 1);
+ else
+ RESETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap))
+ SETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for LDPC coding capability yet */
+ if (ISSUPP_RXLDPC(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_LDPCCODINGCAP(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_LDPCCODINGCAP(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for TX STBC yet */
+ if (ISSUPP_TXSTBC(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for Delayed BACK yet */
+ if (GET_DELAYEDBACK(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
+
+ /* Need change to support 8k AMSDU receive */
+ RESETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function fills the HT cap tlv
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+void
+wlan_fill_ht_cap_tlv(mlan_private * priv,
+ MrvlIETypes_HTCap_t * pht_cap, t_u8 bands)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ int rx_mcs_supp;
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
+
+ /* Fill HT cap info */
+ wlan_fill_cap_info(priv, pht_cap, bands);
+ pht_cap->ht_cap.ht_cap_info = wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
+
+ /* Set ampdu param */
+ SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
+ SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
+
+ rx_mcs_supp = GET_RXMCSSUPP(pmadapter->usr_dev_mcs_support);
+ /* Set MCS for 1x1/2x2 */
+ memset(pmadapter, (t_u8 *) pht_cap->ht_cap.supported_mcs_set, 0xff,
+ rx_mcs_supp);
+ /* Clear all the other values */
+ memset(pmadapter, (t_u8 *) & pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp],
+ 0, NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
+ SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
+
+ /* Clear RD responder bit */
+ RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
+ pht_cap->ht_cap.ht_ext_cap = wlan_cpu_to_le16(pht_cap->ht_cap.ht_ext_cap);
+
+ /* Set Tx BF cap */
+ pht_cap->ht_cap.tx_bf_cap = wlan_cpu_to_le32(priv->tx_bf_cap);
+
+ LEAVE();
+ return;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function prints the 802.11n device capability
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cap Capability value
+ *
+ * @return N/A
+ */
+void
+wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n",
+ (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
+ PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n",
+ (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n",
+ (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n",
+ (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n",
+ (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
+ (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
+ (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n",
+ (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n",
+ (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n",
+ (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n",
+ GET_DELAYEDBACK(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n",
+ GET_IMMEDIATEBACK(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
+
+ if (ISSUPP_RXANTENNAA(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna A\n");
+ }
+ if (ISSUPP_RXANTENNAB(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna B\n");
+ }
+ if (ISSUPP_RXANTENNAC(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna C\n");
+ }
+ if (ISSUPP_RXANTENNAD(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna D\n");
+ }
+ if (ISSUPP_TXANTENNAA(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna A\n");
+ }
+ if (ISSUPP_TXANTENNAB(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna B\n");
+ }
+ if (ISSUPP_TXANTENNAC(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna C\n");
+ }
+ if (ISSUPP_TXANTENNAD(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna D\n");
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prints the 802.11n device MCS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param support Support value
+ *
+ * @return N/A
+ */
+void
+wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: MCSs for %dx%d MIMO\n", GET_RXMCSSUPP(support),
+ GET_TXMCSSUPP(support));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ int tid;
+ TxBAStreamTbl *ptx_ba_tbl;
+ HostCmd_DS_11N_DELBA *pdel_ba =
+ (HostCmd_DS_11N_DELBA *) & resp->params.del_ba;
+
+ ENTER();
+
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+ if (pdel_ba->del_result == BA_RESULT_SUCCESS) {
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_SENT,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set));
+
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS)))
+ {
+ wlan_send_addba(priv, ptx_ba_tbl->tid, ptx_ba_tbl->ra);
+ }
+ } else { /*
+ * In case of failure, recreate the deleted stream in
+ * case we initiated the ADDBA
+ */
+ if (INITIATOR_BIT(pdel_ba->del_ba_param_set)) {
+ wlan_11n_create_txbastream_tbl(priv, pdel_ba->peer_mac_addr, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS)))
+ {
+ mlan_11n_delete_bastream_tbl(priv, ptx_ba_tbl->tid,
+ ptx_ba_tbl->ra, TYPE_DELBA_SENT,
+ MTRUE);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * add a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_addba_req(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ t_u8 tid;
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
+ (HostCmd_DS_11N_ADDBA_RSP *) & resp->params.add_ba_rsp;
+ TxBAStreamTbl *ptx_ba_tbl;
+ raListTbl *ra_list = MNULL;
+
+ ENTER();
+
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo = wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = (wlan_le16_to_cpu(padd_ba_rsp->ssn)) & SSN_MASK;
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_tbl(priv, tid,
+ padd_ba_rsp->
+ peer_mac_addr))) {
+ PRINTM(MCMND,
+ "ADDBA REQ: %02x:%02x:%02x:%02x:%02x:%02x tid=%d ssn=%d win_size=%d,amsdu=%d\n",
+ padd_ba_rsp->peer_mac_addr[0], padd_ba_rsp->peer_mac_addr[1],
+ padd_ba_rsp->peer_mac_addr[2], padd_ba_rsp->peer_mac_addr[3],
+ padd_ba_rsp->peer_mac_addr[4], padd_ba_rsp->peer_mac_addr[5],
+ tid, padd_ba_rsp->ssn,
+ ((padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK) >>
+ BLOCKACKPARAM_WINSIZE_POS),
+ padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK);
+ ptx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
+ if ((padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ ptx_ba_tbl->amsdu = MTRUE;
+ else
+ ptx_ba_tbl->amsdu = MFALSE;
+ } else {
+ PRINTM(MERROR, "BA stream not created\n");
+ }
+ } else {
+ mlan_11n_delete_bastream_tbl(priv, tid, padd_ba_rsp->peer_mac_addr,
+ TYPE_DELBA_SENT, MTRUE);
+ if (padd_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ disable_station_ampdu(priv, tid, padd_ba_rsp->peer_mac_addr);
+#endif /* UAP_SUPPORT */
+ priv->aggr_prio_tbl[tid].ampdu_ap = BA_STREAM_NOT_ALLOWED;
+
+ } else {
+ /* reset packet threshold */
+ ra_list =
+ wlan_wmm_get_ralist_node(priv, tid, padd_ba_rsp->peer_mac_addr);
+ if (ra_list) {
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(priv->adapter);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reconfigure tx buf
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_recfg_tx_buf(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_TXBUF_CFG *ptx_buf = &cmd->params.tx_buf;
+ t_u16 action = (t_u16) cmd_action;
+ t_u16 buf_size = *((t_u16 *) pdata_buf);
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TXBUF_CFG)
+ + S_DS_GEN);
+ ptx_buf->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ PRINTM(MCMND, "set tx_buf = %d\n", buf_size);
+ ptx_buf->buff_size = wlan_cpu_to_le16(buf_size);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ ptx_buf->buff_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of amsdu aggr control
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_AMSDU_AGGR_CTRL *pamsdu_ctrl = &cmd->params.amsdu_aggr_ctrl;
+ t_u16 action = (t_u16) cmd_action;
+ mlan_ds_11n_amsdu_aggr_ctrl *aa_ctrl = (mlan_ds_11n_amsdu_aggr_ctrl *)
+ pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_AMSDU_AGGR_CTRL)
+ + S_DS_GEN);
+ pamsdu_ctrl->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ pamsdu_ctrl->enable = wlan_cpu_to_le16(aa_ctrl->enable);
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of amsdu aggr ctrl
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_AMSDU_AGGR_CTRL *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ cfg->param.amsdu_aggr_ctrl.enable =
+ wlan_le16_to_cpu(amsdu_ctrl->enable);
+ cfg->param.amsdu_aggr_ctrl.curr_buf_size =
+ wlan_le16_to_cpu(amsdu_ctrl->curr_buf_size);
+