summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm/nvidia/tegra_parameters.txt10
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--arch/arm/Kconfig16
-rw-r--r--arch/arm/configs/tegra3_android_defconfig14
-rw-r--r--arch/arm/configs/tegra3_defconfig5
-rw-r--r--arch/arm/configs/tegra_android_defconfig3
-rw-r--r--arch/arm/configs/tegra_defconfig5
-rw-r--r--arch/arm/configs/tegra_p1852_gnu_linux_defconfig22
-rw-r--r--arch/arm/configs/tegra_p852_gnu_linux_defconfig1
-rw-r--r--arch/arm/include/asm/proc-fns.h8
-rw-r--r--arch/arm/include/asm/suspend.h17
-rw-r--r--arch/arm/kernel/Makefile2
-rw-r--r--arch/arm/kernel/sleep.S90
-rw-r--r--arch/arm/kernel/suspend.c72
-rw-r--r--arch/arm/mach-tegra/Kconfig23
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/apbio.c24
-rw-r--r--arch/arm/mach-tegra/apbio.h12
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.c807
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.h22
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power2.c525
-rw-r--r--arch/arm/mach-tegra/board-aruba-panel.c2
-rw-r--r--arch/arm/mach-tegra/board-cardhu-kbc.c7
-rw-r--r--arch/arm/mach-tegra/board-cardhu-memory.c360
-rw-r--r--arch/arm/mach-tegra/board-cardhu-panel.c13
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pinmux.c8
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c8
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c15
-rw-r--r--arch/arm/mach-tegra/board-cardhu-power.c27
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sdhci.c57
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sensors.c117
-rw-r--r--arch/arm/mach-tegra/board-cardhu.c65
-rw-r--r--arch/arm/mach-tegra/board-cardhu.h2
-rw-r--r--arch/arm/mach-tegra/board-enterprise-memory.c735
-rw-r--r--arch/arm/mach-tegra/board-enterprise-panel.c74
-rw-r--r--arch/arm/mach-tegra/board-enterprise-pinmux.c2
-rw-r--r--arch/arm/mach-tegra/board-enterprise-power.c15
-rw-r--r--arch/arm/mach-tegra/board-enterprise-sdhci.c29
-rw-r--r--arch/arm/mach-tegra/board-enterprise.c17
-rw-r--r--arch/arm/mach-tegra/board-harmony-panel.c2
-rw-r--r--arch/arm/mach-tegra/board-harmony.c6
-rw-r--r--arch/arm/mach-tegra/board-kai-memory.c148
-rw-r--r--arch/arm/mach-tegra/board-kai-panel.c21
-rw-r--r--arch/arm/mach-tegra/board-kai-pinmux.c3
-rw-r--r--arch/arm/mach-tegra/board-kai-power.c8
-rw-r--r--arch/arm/mach-tegra/board-kai-sdhci.c48
-rw-r--r--arch/arm/mach-tegra/board-kai-sensors.c120
-rw-r--r--arch/arm/mach-tegra/board-kai.c9
-rw-r--r--arch/arm/mach-tegra/board-kai.h2
-rw-r--r--arch/arm/mach-tegra/board-p1852-panel.c2
-rw-r--r--arch/arm/mach-tegra/board-p1852-pinmux.c4
-rw-r--r--arch/arm/mach-tegra/board-p1852.c17
-rw-r--r--arch/arm/mach-tegra/board-touch-raydium_spi.c6
-rw-r--r--arch/arm/mach-tegra/board-touch.h25
-rw-r--r--arch/arm/mach-tegra/board-ventana-panel.c28
-rw-r--r--arch/arm/mach-tegra/board-ventana-pinmux.c4
-rw-r--r--arch/arm/mach-tegra/board-ventana-power.c4
-rw-r--r--arch/arm/mach-tegra/board-ventana-sdhci.c23
-rw-r--r--arch/arm/mach-tegra/board-ventana-sensors.c20
-rw-r--r--arch/arm/mach-tegra/board-whistler-panel.c21
-rw-r--r--arch/arm/mach-tegra/board-whistler-pinmux.c14
-rw-r--r--arch/arm/mach-tegra/board-whistler-sdhci.c23
-rw-r--r--arch/arm/mach-tegra/board-whistler.c3
-rw-r--r--arch/arm/mach-tegra/board.h27
-rw-r--r--arch/arm/mach-tegra/clock.c32
-rw-r--r--arch/arm/mach-tegra/clock.h1
-rw-r--r--arch/arm/mach-tegra/common.c237
-rw-r--r--arch/arm/mach-tegra/cpu-tegra3.c14
-rw-r--r--arch/arm/mach-tegra/cpuidle-t2.c5
-rw-r--r--arch/arm/mach-tegra/cpuidle-t3.c3
-rw-r--r--arch/arm/mach-tegra/devices.c4
-rw-r--r--arch/arm/mach-tegra/dma.c14
-rw-r--r--arch/arm/mach-tegra/dvfs.h2
-rw-r--r--arch/arm/mach-tegra/fuse.c74
-rw-r--r--arch/arm/mach-tegra/headsmp.S8
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h7
-rw-r--r--arch/arm/mach-tegra/include/mach/dma.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/hdmi-audio.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/io.h10
-rw-r--r--arch/arm/mach-tegra/include/mach/sdhci.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h6
-rw-r--r--arch/arm/mach-tegra/include/mach/thermal.h6
-rw-r--r--arch/arm/mach-tegra/io.c6
-rw-r--r--arch/arm/mach-tegra/iovmm-smmu.c52
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-panel.c2
-rw-r--r--arch/arm/mach-tegra/pcie.c23
-rw-r--r--arch/arm/mach-tegra/pinmux-t2-tables.c4
-rw-r--r--arch/arm/mach-tegra/pinmux-t3-tables.c442
-rw-r--r--arch/arm/mach-tegra/platsmp.c5
-rw-r--r--arch/arm/mach-tegra/pm.c89
-rw-r--r--arch/arm/mach-tegra/powergate.c6
-rw-r--r--arch/arm/mach-tegra/sleep-t2.S47
-rw-r--r--arch/arm/mach-tegra/sleep-t3.S34
-rw-r--r--arch/arm/mach-tegra/sleep.S269
-rw-r--r--arch/arm/mach-tegra/sleep.h69
-rw-r--r--arch/arm/mach-tegra/syncpt.c100
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c167
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c45
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c126
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.c71
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.h3
-rw-r--r--arch/arm/mach-tegra/tegra3_speedo.c37
-rw-r--r--arch/arm/mach-tegra/tegra3_thermal.c97
-rw-r--r--arch/arm/mach-tegra/tegra3_throttle.c153
-rw-r--r--arch/arm/mach-tegra/tegra_usb_modem_power.c232
-rw-r--r--arch/arm/mach-tegra/usb_phy.c24
-rw-r--r--arch/arm/mach-tegra/wdt-recovery.c2
-rw-r--r--arch/arm/mm/cache-l2x0.c2
-rw-r--r--arch/arm/mm/proc-arm920.S21
-rw-r--r--arch/arm/mm/proc-arm926.S21
-rw-r--r--arch/arm/mm/proc-sa1100.S25
-rw-r--r--arch/arm/mm/proc-v6.S44
-rw-r--r--arch/arm/mm/proc-v7.S74
-rw-r--r--arch/arm/mm/proc-xsc3.S28
-rw-r--r--arch/arm/mm/proc-xscale.S25
-rw-r--r--arch/arm/oprofile/common.c22
-rw-r--r--arch/arm/vfp/vfpmodule.c10
-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
-rw-r--r--include/linux/bitops.h6
-rw-r--r--include/linux/clk.h32
-rw-r--r--include/linux/cpufreq.h1
-rw-r--r--include/linux/device.h21
-rw-r--r--include/linux/i2c.h13
-rw-r--r--include/linux/i2c/twl.h16
-rwxr-xr-xinclude/linux/interrupt_keys.h47
-rw-r--r--include/linux/nct1008.h3
-rw-r--r--include/linux/nvhost.h62
-rw-r--r--include/linux/nvmap.h (renamed from arch/arm/mach-tegra/include/mach/nvmap.h)7
-rw-r--r--include/linux/platform_device.h9
-rw-r--r--include/linux/regmap.h31
-rw-r--r--include/linux/regulator/gpio-switch-regulator.h69
-rw-r--r--include/linux/regulator/max8973-regulator.h77
-rw-r--r--include/linux/regulator/tps6238x0-regulator.h46
-rw-r--r--include/linux/smb349-charger.h2
-rw-r--r--include/linux/tegra_audio.h2
-rw-r--r--include/linux/wl12xx.h4
-rw-r--r--include/media/nvc.h1
-rw-r--r--include/media/ov5640.h64
-rw-r--r--include/media/ov5650.h6
-rw-r--r--include/media/sh532u.h44
-rw-r--r--include/media/tegra_camera.h3
-rw-r--r--include/trace/events/nvhost.h65
-rw-r--r--include/trace/events/power.h22
-rw-r--r--include/trace/events/regmap.h36
-rw-r--r--include/video/tegra_dc_ext.h5
-rw-r--r--security/tf_driver/s_version.h4
-rw-r--r--security/tf_driver/tf_comm.c56
-rw-r--r--security/tf_driver/tf_device.c19
-rw-r--r--sound/pci/hda/hda_eld.c5
-rw-r--r--sound/pci/hda/patch_hdmi.c6
-rw-r--r--sound/soc/codecs/Makefile3
-rw-r--r--sound/soc/codecs/aic326x_tiload.c5
-rw-r--r--sound/soc/codecs/base_main_Rate48_pps_driver.h11
-rw-r--r--sound/soc/codecs/rt5639.c16
-rw-r--r--sound/soc/codecs/rt5640.c47
-rw-r--r--sound/soc/codecs/second_rate_pps_driver.h7
-rw-r--r--sound/soc/codecs/spdif_transciever.c38
-rw-r--r--sound/soc/codecs/tlv320aic326x.c24
-rw-r--r--sound/soc/codecs/tlv320aic326x.h11
-rw-r--r--sound/soc/codecs/tlv320aic326x_mini-dsp.c32
-rw-r--r--sound/soc/codecs/tlv320aic326x_minidsp_config.c11
-rw-r--r--sound/soc/codecs/wm8903.c8
-rw-r--r--sound/soc/sh/siu_pcm.c5
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_i2s.c3
-rw-r--r--sound/soc/tegra/tegra30_ahub.c127
-rw-r--r--sound/soc/tegra/tegra30_ahub.h14
-rw-r--r--sound/soc/tegra/tegra30_i2s.c241
-rw-r--r--sound/soc/tegra/tegra30_i2s.h14
-rw-r--r--sound/soc/tegra/tegra_aic326x.c8
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c4
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h3
-rw-r--r--sound/soc/tegra/tegra_max98088.c20
-rw-r--r--sound/soc/tegra/tegra_max98095.c2
-rw-r--r--sound/soc/tegra/tegra_p1852.c2
-rw-r--r--sound/soc/tegra/tegra_pcm.c107
-rw-r--r--sound/soc/tegra/tegra_pcm.h20
-rw-r--r--sound/soc/tegra/tegra_rt5640.c59
-rw-r--r--sound/soc/tegra/tegra_tdm_pcm.c160
-rw-r--r--sound/soc/tegra/tegra_wm8753.c2
-rw-r--r--sound/soc/tegra/tegra_wm8903.c2
-rw-r--r--sound/soc/tegra/trimslice.c2
417 files changed, 121239 insertions, 5245 deletions
diff --git a/Documentation/arm/nvidia/tegra_parameters.txt b/Documentation/arm/nvidia/tegra_parameters.txt
index 4c73fe7269f3..39ab662df761 100644
--- a/Documentation/arm/nvidia/tegra_parameters.txt
+++ b/Documentation/arm/nvidia/tegra_parameters.txt
@@ -167,3 +167,13 @@ Contains voltage state.
/sys/kernel/debug/clock/mon.avp/rate
------------------------------------
+
+/sys/kernel/debug/clock/rails
+-----------------------------
+
+Contains the time at each voltage.
+
+/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state
+--------------------------------------------------------
+
+Contains the time at each frequency.
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 10c64c8a13d4..6346042c3b54 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -267,3 +267,7 @@ IOMAP
pcim_iounmap()
pcim_iomap_table() : array of mapped addresses indexed by BAR
pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
+
+CLOCK
+ devm_clk_get()
+ devm_clk_put()
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3c3b868948aa..5132b50295eb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1155,6 +1155,14 @@ config ARM_ERRATA_460075
ACTLR register. Note that setting specific bits in the ACTLR register
may not be available in non-secure mode.
+config ARM_ERRATA_716044
+ bool "ARM errata: an uncacheable load multiple instruction can cause a deadlock"
+ depends on CPU_V7
+ help
+ Under some rare circumstances, an uncacheable load multiple
+ instruction (LDRD, LDM, VLDM, VLD1, VLD2, VLD3, VLD4) can cause
+ a processor deadlock.
+
config ARM_ERRATA_742230
bool "ARM errata: DMB operation may be faulty"
depends on CPU_V7 && SMP
@@ -1688,6 +1696,14 @@ config HW_PERF_EVENTS
Enable hardware performance counter support for perf events. If
disabled, perf events will use software events only.
+config ARCH_HAS_SUSPEND_PAGETABLE
+ bool
+ help
+ This option indicates the platform architecture installs its own
+ 1:1 pagetable during CPU suspend/resume codepaths. This means the
+ patching of the pagetable as part of reenabling the MMU isn't
+ needed in the ARM common CPU resume codepath. If in doubt, say N.
+
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
diff --git a/arch/arm/configs/tegra3_android_defconfig b/arch/arm/configs/tegra3_android_defconfig
index 92a9e94254be..ba20b0ee943f 100644
--- a/arch/arm/configs/tegra3_android_defconfig
+++ b/arch/arm/configs/tegra3_android_defconfig
@@ -234,6 +234,8 @@ CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y
CONFIG_BCMDHD_HW_OOB=y
CONFIG_BCMDHD_CSCAN_ENABLE=y
CONFIG_BCMDHD_INSMOD_NO_FW_LOAD=y
+# CONFIG_BCMDHD_CUSTOM_REGULATORY_DOMAIN is not set
+CONFIG_SD8797=m
CONFIG_WL12XX_MENU=m
CONFIG_WL12XX=m
CONFIG_WL12XX_SDIO=m
@@ -311,10 +313,14 @@ CONFIG_MFD_RICOH583=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_MAX77663=y
CONFIG_REGULATOR_TPS6586X=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS6238X0=y
CONFIG_REGULATOR_TPS6591X=y
CONFIG_REGULATOR_TPS80031=y
CONFIG_REGULATOR_RICOH583=y
@@ -327,6 +333,7 @@ CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
# CONFIG_TEGRA_MEDIASERVER is not set
CONFIG_TEGRA_NVAVP=y
CONFIG_VIDEO_OV5650=y
+CONFIG_VIDEO_OV5640=y
CONFIG_VIDEO_OV9726=y
CONFIG_VIDEO_OV2710=y
CONFIG_VIDEO_AR0832=y
@@ -379,7 +386,7 @@ CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_SERIAL_BASEBAND=m
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_G_ANDROID=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
@@ -434,6 +441,7 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DEBUG_FS=y
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_DETECT_HUNG_TASK is not set
@@ -442,6 +450,10 @@ CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_FUNCTION_GRAPH_TRACER is not set
+CONFIG_TRACEDUMP=y
+CONFIG_TRACEDUMP_PROCFS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_SHA256=y
diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig
index cb78209e7b42..2d895fef4cac 100644
--- a/arch/arm/configs/tegra3_defconfig
+++ b/arch/arm/configs/tegra3_defconfig
@@ -39,6 +39,7 @@ CONFIG_TEGRA_BB_XMM_POWER=y
CONFIG_TEGRA_BB_XMM_POWER2=m
CONFIG_TEGRA_PLLM_RESTRICTED=y
CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_TEGRA_PREPOWER_WIFI=y
CONFIG_ARM_ERRATA_742230=y
CONFIG_ARM_ERRATA_743622=y
CONFIG_ARM_ERRATA_751472=y
@@ -192,7 +193,6 @@ CONFIG_AD525X_DPOT_I2C=y
CONFIG_ICS932S401=y
CONFIG_APDS9802ALS=y
CONFIG_ISL29003=y
-CONFIG_SENSORS_AK8975=y
CONFIG_SENSORS_NCT1008=y
CONFIG_UID_STAT=y
CONFIG_BCM4329_RFKILL=y
@@ -300,6 +300,7 @@ CONFIG_MFD_RICOH583=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
CONFIG_REGULATOR_MAX8907C=y
CONFIG_REGULATOR_MAX77663=y
CONFIG_REGULATOR_TPS6586X=y
@@ -364,7 +365,7 @@ CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_SERIAL_BASEBAND=m
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_MASS_STORAGE=m
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/tegra_android_defconfig b/arch/arm/configs/tegra_android_defconfig
index 053b374d0ff6..a129a8ee5a10 100644
--- a/arch/arm/configs/tegra_android_defconfig
+++ b/arch/arm/configs/tegra_android_defconfig
@@ -214,6 +214,7 @@ CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y
CONFIG_BCMDHD_HW_OOB=y
CONFIG_BCMDHD_CSCAN_ENABLE=y
CONFIG_BCMDHD_INSMOD_NO_FW_LOAD=y
+# CONFIG_BCMDHD_CUSTOM_REGULATORY_DOMAIN is not set
CONFIG_USB_USBNET=y
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_BELKIN is not set
@@ -323,7 +324,7 @@ CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_G_ANDROID=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 6e51d191aa5e..aa9f7dffac11 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -37,6 +37,8 @@ CONFIG_TEGRA_EMC_SCALING_ENABLE=y
CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
CONFIG_USB_HOTPLUG=y
CONFIG_TEGRA_USB_MODEM_POWER=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_TEGRA_PREPOWER_WIFI=y
CONFIG_ARM_ERRATA_720789=y
CONFIG_ARM_ERRATA_751472=y
CONFIG_NO_HZ=y
@@ -189,7 +191,6 @@ CONFIG_AD525X_DPOT=y
CONFIG_AD525X_DPOT_I2C=y
CONFIG_APDS9802ALS=y
CONFIG_ISL29003=y
-CONFIG_SENSORS_AK8975=y
CONFIG_SENSORS_NCT1008=y
CONFIG_UID_STAT=y
CONFIG_BCM4329_RFKILL=y
@@ -327,7 +328,7 @@ CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_MASS_STORAGE=m
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
index 594b078a27a2..6a98b5b8fb49 100644
--- a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
+++ b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
@@ -13,12 +13,11 @@ CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_PANIC_TIMEOUT=10
-CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
@@ -27,20 +26,21 @@ CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
CONFIG_ARCH_TEGRA=y
+CONFIG_GPIO_PCA953X=y
CONFIG_ARCH_TEGRA_3x_SOC=y
CONFIG_TEGRA_PCI=y
CONFIG_MACH_P1852=y
-CONFIG_TEGRA_DEBUG_UARTB=y
CONFIG_TEGRA_PWM=y
# CONFIG_TEGRA_CPU_DVFS is not set
CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
-CONFIG_TEGRA_MC_PROFILE=y
+# CONFIG_TEGRA_MC_EARLY_ACK is not set
CONFIG_ARM_ERRATA_743622=y
CONFIG_ARM_ERRATA_751472=y
CONFIG_ARM_ERRATA_752520=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
+CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
# CONFIG_OABI_COMPAT is not set
@@ -50,6 +50,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE="mem=448@2048M console=ttyS0,115200n8 earlyprintk init=/bin/ash"
CONFIG_VFP=y
CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -75,7 +76,6 @@ CONFIG_IPV6_MULTIPLE_TABLES=y
# CONFIG_ANDROID_PARANOID_NETWORK is not set
# CONFIG_FIRMWARE_IN_KERNEL is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
@@ -88,7 +88,6 @@ CONFIG_MTD_NOR_TEGRA=y
CONFIG_MTD_NAND_TEGRA=y
CONFIG_MTD_NAND=y
CONFIG_BLK_DEV_LOOP=y
-# CONFIG_ANDROID_PMEM is not set
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_LOWLEVEL is not set
@@ -112,10 +111,10 @@ CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_TEGRA=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_TEGRA=y
-# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
@@ -126,7 +125,6 @@ CONFIG_SPI_TEGRA=y
CONFIG_SPI_SLAVE_TEGRA=y
CONFIG_SPI_SPIDEV=y
CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_PCA953X=y
CONFIG_POWER_SUPPLY=y
CONFIG_PDA_POWER=y
CONFIG_BATTERY_BQ20Z75=y
@@ -167,18 +165,19 @@ CONFIG_USB_STORAGE=y
CONFIG_USB_LIBUSUAL=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
+CONFIG_MMC_BKOPS=y
CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MMC_EMBEDDED_SDIO=y
CONFIG_MMC_PARANOID_SD_INIT=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_TEGRA=y
CONFIG_SWITCH=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_TEGRA=y
CONFIG_STAGING=y
-# CONFIG_STAGING_EXCLUDE_BUILD is not set
CONFIG_IIO=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
@@ -198,7 +197,6 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_ROOT_NFS=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
CONFIG_NLS_CODEPAGE_437=y
@@ -206,17 +204,13 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_VM=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_ARM_UNWIND is not set
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ARC4=y
diff --git a/arch/arm/configs/tegra_p852_gnu_linux_defconfig b/arch/arm/configs/tegra_p852_gnu_linux_defconfig
index 7539158200c1..9f7e71711c4f 100644
--- a/arch/arm/configs/tegra_p852_gnu_linux_defconfig
+++ b/arch/arm/configs/tegra_p852_gnu_linux_defconfig
@@ -248,6 +248,7 @@ CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
+CONFIG_MMC_BKOPS=y
CONFIG_MMC_UNSAFE_RESUME=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_SDHCI=y
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 9e92cb205e65..633d1cb84d87 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -81,10 +81,6 @@ extern void cpu_dcache_clean_area(void *, int);
extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
-
-/* These three are private to arch/arm/kernel/suspend.c */
-extern void cpu_do_suspend(void *);
-extern void cpu_do_resume(void *);
#else
#define cpu_proc_init processor._proc_init
#define cpu_proc_fin processor._proc_fin
@@ -93,10 +89,6 @@ extern void cpu_do_resume(void *);
#define cpu_dcache_clean_area processor.dcache_clean_area
#define cpu_set_pte_ext processor.set_pte_ext
#define cpu_do_switch_mm processor.switch_mm
-
-/* These three are private to arch/arm/kernel/suspend.c */
-#define cpu_do_suspend processor.do_suspend
-#define cpu_do_resume processor.do_resume
#endif
extern void cpu_resume(void);
diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
index 1c0a551ae375..b0e4e1a02318 100644
--- a/arch/arm/include/asm/suspend.h
+++ b/arch/arm/include/asm/suspend.h
@@ -1,7 +1,22 @@
#ifndef __ASM_ARM_SUSPEND_H
#define __ASM_ARM_SUSPEND_H
+#include <asm/memory.h>
+#include <asm/tlbflush.h>
+
extern void cpu_resume(void);
-extern int cpu_suspend(unsigned long, int (*)(unsigned long));
+
+/*
+ * Hide the first two arguments to __cpu_suspend - these are an implementation
+ * detail which platform code shouldn't have to know about.
+ */
+static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+ extern int __cpu_suspend(int, long, unsigned long,
+ int (*)(unsigned long));
+ int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn);
+ flush_tlb_all();
+ return ret;
+}
#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 6e84750cdbe8..b6f3c9f80ea7 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o
obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
-obj-$(CONFIG_PM_SLEEP) += sleep.o suspend.o
+obj-$(CONFIG_PM_SLEEP) += sleep.o
obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_SMP) += smp.o smp_tlb.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index 3f4a517f5b97..714664b2b2ee 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -8,62 +8,96 @@
.text
/*
- * Save CPU state for a suspend. This saves the CPU general purpose
- * registers, and allocates space on the kernel stack to save the CPU
- * specific registers and some other data for resume.
- * r0 = suspend function arg0
- * r1 = suspend function
+ * Save CPU state for a suspend
+ * r1 = v:p offset
+ * r2 = suspend function arg0
+ * r3 = suspend function
*/
ENTRY(__cpu_suspend)
stmfd sp!, {r4 - r11, lr}
#ifdef MULTI_CPU
ldr r10, =processor
- ldr r4, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
+ ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
+ ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function
#else
- ldr r4, =cpu_suspend_size
+ ldr r5, =cpu_suspend_size
+ ldr ip, =cpu_do_resume
#endif
- mov r5, sp @ current virtual SP
- add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn
- sub sp, sp, r4 @ allocate CPU state on stack
- stmfd sp!, {r0, r1} @ save suspend func arg and pointer
- add r0, sp, #8 @ save pointer to save block
- mov r1, r4 @ size of save block
- mov r2, r5 @ virtual SP
- ldr r3, =sleep_save_sp
+ mov r6, sp @ current virtual SP
+ sub sp, sp, r5 @ allocate CPU state on stack
+ mov r0, sp @ save pointer to CPU save block
+ add ip, ip, r1 @ convert resume fn to phys
+ stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn
+ ldr r5, =sleep_save_sp
+ add r6, sp, r1 @ convert SP to phys
+ stmfd sp!, {r2, r3} @ save suspend func arg and pointer
#ifdef CONFIG_SMP
ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
ALT_UP(mov lr, #0)
and lr, lr, #15
- add r3, r3, lr, lsl #2
+ str r6, [r5, lr, lsl #2] @ save phys SP
+#else
+ str r6, [r5] @ save phys SP
+#endif
+#ifdef MULTI_CPU
+ mov lr, pc
+ ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state
+#else
+ bl cpu_do_suspend
+#endif
+
+ @ flush data cache
+#ifdef MULTI_CACHE
+ ldr r10, =cpu_cache
+ mov lr, pc
+ ldr pc, [r10, #CACHE_FLUSH_KERN_ALL]
+#else
+ bl __cpuc_flush_kern_all
#endif
- bl __cpu_suspend_save
adr lr, BSYM(cpu_suspend_abort)
ldmfd sp!, {r0, pc} @ call suspend fn
ENDPROC(__cpu_suspend)
.ltorg
cpu_suspend_abort:
- ldmia sp!, {r1 - r3} @ pop phys pgd, virt SP, phys resume fn
- teq r0, #0
- moveq r0, #1 @ force non-zero value
+ ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn
mov sp, r2
ldmfd sp!, {r4 - r11, pc}
ENDPROC(cpu_suspend_abort)
/*
* r0 = control register value
+ * r1 = v:p offset (preserved by cpu_do_resume)
+ * r2 = phys page table base
+ * r3 = L1 section flags
*/
- .align 5
ENTRY(cpu_resume_mmu)
+#ifndef CONFIG_ARCH_HAS_SUSPEND_PAGETABLE
+ adr r4, cpu_resume_turn_mmu_on
+ mov r4, r4, lsr #20
+ orr r3, r3, r4, lsl #20
+ ldr r5, [r2, r4, lsl #2] @ save old mapping
+ str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code
+ sub r2, r2, r1
+#endif
ldr r3, =cpu_resume_after_mmu
- mcr p15, 0, r0, c1, c0, 0 @ turn on MMU, I-cache, etc
- mrc p15, 0, r0, c0, c0, 0 @ read id reg
- mov r0, r0
- mov r0, r0
- mov pc, r3 @ jump to virtual address
+ bic r1, r0, #CR_C @ ensure D-cache is disabled
+ b cpu_resume_turn_mmu_on
ENDPROC(cpu_resume_mmu)
+ .ltorg
+ .align 5
+cpu_resume_turn_mmu_on:
+ mcr p15, 0, r1, c1, c0, 0 @ turn on MMU, I-cache, etc
+ mrc p15, 0, r1, c0, c0, 0 @ read id reg
+ mov r1, r1
+ mov r1, r1
+ mov pc, r3 @ jump to virtual address
+ENDPROC(cpu_resume_turn_mmu_on)
cpu_resume_after_mmu:
- bl cpu_init
+#ifndef CONFIG_ARCH_HAS_SUSPEND_PAGETABLE
+ str r5, [r2, r4, lsl #2] @ restore old mapping
+#endif
+ mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache
mov r0, #0 @ return zero on success
ldmfd sp!, {r4 - r11, pc}
ENDPROC(cpu_resume_after_mmu)
@@ -88,7 +122,7 @@ ENTRY(cpu_resume)
ldr r0, sleep_save_sp @ stack phys addr
#endif
setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off
- @ load phys pgd, stack, resume fn
+ @ load v:p, stack, resume fn
ARM( ldmia r0!, {r1, sp, pc} )
THUMB( ldmia r0!, {r1, r2, r3} )
THUMB( mov sp, r2 )
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
deleted file mode 100644
index 93a22d282c16..000000000000
--- a/arch/arm/kernel/suspend.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include <linux/init.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/memory.h>
-#include <asm/suspend.h>
-#include <asm/tlbflush.h>
-
-static pgd_t *suspend_pgd;
-
-extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
-extern void cpu_resume_mmu(void);
-
-/*
- * This is called by __cpu_suspend() to save the state, and do whatever
- * flushing is required to ensure that when the CPU goes to sleep we have
- * the necessary data available when the caches are not searched.
- */
-void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
-{
- *save_ptr = virt_to_phys(ptr);
-
- /* This must correspond to the LDM in cpu_resume() assembly */
- *ptr++ = virt_to_phys(suspend_pgd);
- *ptr++ = sp;
- *ptr++ = virt_to_phys(cpu_do_resume);
-
- cpu_do_suspend(ptr);
-
- flush_cache_all();
- outer_clean_range(*save_ptr, *save_ptr + ptrsz);
- outer_clean_range(virt_to_phys(save_ptr),
- virt_to_phys(save_ptr) + sizeof(*save_ptr));
-}
-
-/*
- * Hide the first two arguments to __cpu_suspend - these are an implementation
- * detail which platform code shouldn't have to know about.
- */
-int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
-{
- struct mm_struct *mm = current->active_mm;
- int ret;
-
- if (!suspend_pgd)
- return -EINVAL;
-
- /*
- * Provide a temporary page table with an identity mapping for
- * the MMU-enable code, required for resuming. On successful
- * resume (indicated by a zero return code), we need to switch
- * back to the correct page tables.
- */
- ret = __cpu_suspend(arg, fn);
- if (ret == 0) {
- cpu_switch_mm(mm->pgd, mm);
- local_flush_tlb_all();
- }
-
- return ret;
-}
-
-static int __init cpu_suspend_init(void)
-{
- suspend_pgd = pgd_alloc(&init_mm);
- if (suspend_pgd) {
- unsigned long addr = virt_to_phys(cpu_resume_mmu);
- identity_mapping_add(suspend_pgd, addr, addr + SECTION_SIZE);
- }
- return suspend_pgd ? 0 : -ENOMEM;
-}
-core_initcall(cpu_suspend_init);
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 90d66a105154..1aa448c44fcd 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -21,6 +21,8 @@ config ARCH_TEGRA_2x_SOC
select ARCH_SUPPORTS_MSI if TEGRA_PCI
select PCI_MSI if TEGRA_PCI
select CPA
+ select ARM_ERRATA_716044
+ select ARCH_HAS_SUSPEND_PAGETABLE
help
Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -46,6 +48,7 @@ config ARCH_TEGRA_3x_SOC
select ARM_ERRATA_754322
select TEGRA_LP2_ARM_TWD if HAVE_ARM_TWD && !TEGRA_RAIL_OFF_MULTIPLE_CPUS
select CPA
+ select ARCH_HAS_SUSPEND_PAGETABLE
help
Support for NVIDIA Tegra 3 family of SoCs, based upon the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -294,14 +297,6 @@ config TEGRA_IOVMM_SMMU
space through the SMMU (System Memory Management Unit)
hardware included on Tegra SoCs.
-config TEGRA_SMMU_BASE_AT_E0000000
- bool "Force SMMU IOVA base to 0xe0000000"
- depends on TEGRA_IOVMM_SMMU
- default n
- help
- Forces SMMU IOVA base address to 0xe0000000 for debug purposes
- only. Select n for production systems.
-
config TEGRA_IOVMM_SMMU_SYSFS
bool "Enable SMMU register access for debugging"
depends on TEGRA_IOVMM_SMMU
@@ -333,6 +328,7 @@ config TEGRA_THERMAL_THROTTLE
bool "Enable throttling of CPU speed on overtemp"
depends on TEGRA_SILICON_PLATFORM
depends on CPU_FREQ
+ depends on THERMAL
default y
help
Also requires enabling a temperature sensor such as NCT1008.
@@ -453,11 +449,6 @@ config TEGRA_BB_XMM_POWER2
insert this LKM to initiate 2nd USB enumeration power sequence
- after modem software has been downloaded to flashless device.
-config TEGRA_THERMAL_SYSFS
- bool "Enable Thermal driver to use Thermal Sysfs infrastructure"
- depends on THERMAL
- default y
-
config TEGRA_PLLM_RESTRICTED
bool "Restrict PLLM usage as module clock source"
depends on !ARCH_TEGRA_2x_SOC
@@ -494,4 +485,10 @@ config TEGRA_PREINIT_CLOCKS
help
Preinitialize Tegra clocks to known states before actual full-
scale clock initialization starts.
+
+config TEGRA_PREPOWER_WIFI
+ bool "Pre-power up WiFi "
+ default n
+ help
+ Pre-power up the on board WiFi chip
endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 21d43a7096ce..6b1c4c52c713 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += common-t2.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += common-t3.o
obj-y += io.o
obj-y += irq.o
-obj-$(CONFIG_TEGRA_GRHOST) += syncpt.o
obj-y += clock.o
obj-y += clock-common.o
obj-y += timer.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index e227331c2f0f..5f3944993804 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -30,7 +30,7 @@
static DEFINE_MUTEX(tegra_apb_dma_lock);
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
static struct tegra_dma_channel *tegra_apb_dma;
static u32 *tegra_apb_bb;
static dma_addr_t tegra_apb_bb_phys;
@@ -68,6 +68,8 @@ static inline u32 apb_readl(unsigned long offset)
req.source_wrap = 4;
req.req_sel = 0;
req.size = 4;
+ dma_sync_single_for_device(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_FROM_DEVICE);
INIT_COMPLETION(tegra_apb_wait);
@@ -81,6 +83,8 @@ static inline u32 apb_readl(unsigned long offset)
*(u32 *)tegra_apb_bb = 0;
}
+ dma_sync_single_for_cpu(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_FROM_DEVICE);
mutex_unlock(&tegra_apb_dma_lock);
return *((u32 *)tegra_apb_bb);
}
@@ -97,6 +101,8 @@ static inline void apb_writel(u32 value, unsigned long offset)
}
mutex_lock(&tegra_apb_dma_lock);
+ dma_sync_single_for_cpu(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_TO_DEVICE);
*((u32 *)tegra_apb_bb) = value;
req.complete = apb_dma_complete;
req.to_memory = 0;
@@ -111,6 +117,8 @@ static inline void apb_writel(u32 value, unsigned long offset)
INIT_COMPLETION(tegra_apb_wait);
+ dma_sync_single_for_device(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_TO_DEVICE);
tegra_dma_enqueue_req(tegra_apb_dma, &req);
ret = wait_for_completion_timeout(&tegra_apb_wait,
@@ -121,17 +129,6 @@ static inline void apb_writel(u32 value, unsigned long offset)
mutex_unlock(&tegra_apb_dma_lock);
}
-#else
-static inline u32 apb_readl(unsigned long offset)
-{
- return readl(IO_TO_VIRT(offset));
-}
-
-static inline void apb_writel(u32 value, unsigned long offset)
-{
- writel(value, IO_TO_VIRT(offset));
-}
-#endif
u32 tegra_apb_readl(unsigned long offset)
{
@@ -142,10 +139,11 @@ void tegra_apb_writel(u32 value, unsigned long offset)
{
apb_writel(value, offset);
}
+#endif
static int tegra_init_apb_dma(void)
{
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
tegra_apb_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
TEGRA_DMA_SHARED, "apbio");
if (!tegra_apb_dma) {
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
index f0c87f06a209..121fda359e40 100644
--- a/arch/arm/mach-tegra/apbio.h
+++ b/arch/arm/mach-tegra/apbio.h
@@ -15,5 +15,17 @@
*
*/
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
u32 tegra_apb_readl(unsigned long offset);
void tegra_apb_writel(u32 value, unsigned long offset);
+#else
+static inline u32 tegra_apb_readl(unsigned long offset)
+{
+ return readl(IO_TO_VIRT(offset));
+}
+
+static inline void tegra_apb_writel(u32 value, unsigned long offset)
+{
+ writel(value, IO_TO_VIRT(offset));
+}
+#endif
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c
index 7d5c527cab80..20f8d306f901 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power.c
@@ -30,8 +30,11 @@
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
+#include <linux/pm_qos_params.h>
#include <mach/usb_phy.h>
#include "board.h"
+#include "board-enterprise.h"
#include "devices.h"
#include "gpio-names.h"
#include "baseband-xmm-power.h"
@@ -87,12 +90,12 @@ static enum {
IPC_AP_WAKE_H,
} ipc_ap_wake_state;
-enum baseband_xmm_powerstate_t baseband_xmm_powerstate;
+static enum baseband_xmm_powerstate_t baseband_xmm_powerstate;
static struct workqueue_struct *workqueue;
static struct work_struct init1_work;
static struct work_struct init2_work;
static struct work_struct L2_resume_work;
-static struct baseband_power_platform_data *baseband_power_driver_data;
+static struct work_struct autopm_resume_work;
static bool register_hsic_device;
static struct wake_lock wakelock;
static struct usb_device *usbdev;
@@ -100,64 +103,133 @@ static bool CP_initiated_L2toL0;
static bool modem_power_on;
static int power_onoff;
static int reenable_autosuspend;
-static struct work_struct autopm_resume_work;
static bool wakeup_pending;
static bool modem_sleep_flag;
static spinlock_t xmm_lock;
static DEFINE_MUTEX(xmm_onoff_mutex);
+static bool system_suspending;
+static struct regulator *enterprise_hsic_reg;
+static bool _hsic_reg_status;
+static struct pm_qos_request_list boost_cpu_freq_req;
+static struct delayed_work pm_qos_work;
+#define BOOST_CPU_FREQ_MIN 1500000
+
+/* driver specific data - same structure is used for flashless
+ * & flashed modem drivers i.e. baseband-xmm-power2.c
+ */
+struct xmm_power_data xmm_power_drv_data;
+EXPORT_SYMBOL(xmm_power_drv_data);
-static void baseband_xmm_power_L2_resume(void);
-static int baseband_xmm_power_driver_handle_resume(
+static void xmm_power_L2_resume(void);
+static int xmm_power_driver_handle_resume(
struct baseband_power_platform_data *data);
+static int tegra_baseband_rail_on(void)
+{
+ int ret;
+ struct board_info bi;
+ tegra_get_board_info(&bi);
+
+ /* only applicable to enterprise */
+ if (bi.board_id != BOARD_E1197)
+ return 0;
+
+ if (_hsic_reg_status == true)
+ return 0;
+
+ if (enterprise_hsic_reg == NULL) {
+ enterprise_hsic_reg = regulator_get(NULL, "avdd_hsic");
+ if (IS_ERR_OR_NULL(enterprise_hsic_reg)) {
+ pr_err("xmm: could not get regulator vddio_hsic\n");
+ enterprise_hsic_reg = NULL;
+ return PTR_ERR(enterprise_hsic_reg);
+ }
+ }
+ ret = regulator_enable(enterprise_hsic_reg);
+ if (ret < 0) {
+ pr_err("xmm: failed to enable regulator\n");
+ return ret;
+ }
+ _hsic_reg_status = true;
+ return 0;
+}
+
+static int tegra_baseband_rail_off(void)
+{
+ int ret;
+ struct board_info bi;
+ tegra_get_board_info(&bi);
+
+ /* only applicable to enterprise */
+ if (bi.board_id != BOARD_E1197)
+ return 0;
+
+ if (_hsic_reg_status == false)
+ return 0;
+
+ if (IS_ERR_OR_NULL(enterprise_hsic_reg)) {
+ pr_err("xmm: unbalanced disable on vddio_hsic regulator\n");
+ enterprise_hsic_reg = NULL;
+ return PTR_ERR(enterprise_hsic_reg);
+ }
+ ret = regulator_disable(enterprise_hsic_reg);
+ if (ret < 0) {
+ pr_err("xmm: failed to disable regulator\n");
+ return ret;
+ }
+ _hsic_reg_status = false;
+ return 0;
+}
+
static int baseband_modem_power_on(struct baseband_power_platform_data *data)
{
/* set IPC_HSIC_ACTIVE active */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 1);
-
- /* wait 20 ms */
- mdelay(20);
+ gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
/* reset / power on sequence */
- mdelay(40);
+ msleep(40);
gpio_set_value(data->modem.xmm.bb_rst, 1);
mdelay(1);
gpio_set_value(data->modem.xmm.bb_on, 1);
- udelay(40);
+ udelay(70);
gpio_set_value(data->modem.xmm.bb_on, 0);
+ pr_debug("%s: pm qos request CPU 1.5GHz\n", __func__);
+ pm_qos_update_request(&boost_cpu_freq_req, (s32)BOOST_CPU_FREQ_MIN);
+ /* Device enumeration should happen in 1 sec however in any case
+ * we want to request it back to normal so schedule work to restore
+ * CPU freq after 2 seconds */
+ schedule_delayed_work(&pm_qos_work, msecs_to_jiffies(2000));
+
return 0;
}
-static int baseband_xmm_power_on(struct platform_device *device)
+static int xmm_power_on(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *pdata =
device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
int ret;
pr_debug("%s {\n", __func__);
/* check for platform data */
- if (!data) {
- pr_err("%s: !data\n", __func__);
+ if (!pdata) {
+ pr_err("%s: !pdata\n", __func__);
return -EINVAL;
}
if (baseband_xmm_powerstate != BBXMM_PS_UNINIT)
return -EINVAL;
+ tegra_baseband_rail_on();
+
/* reset the state machine */
baseband_xmm_powerstate = BBXMM_PS_INIT;
modem_sleep_flag = false;
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
- if (modem_ver < XMM_MODEM_VER_1130)
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- else
- ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
-
- pr_debug("%s wake_st(%d) modem version %d\n", __func__,
- ipc_ap_wake_state, modem_ver);
+ pr_debug("%s wake_st(%d) modem version %lu\n", __func__,
+ ipc_ap_wake_state, modem_ver);
/* register usb host controller */
if (!modem_flash) {
@@ -167,35 +239,35 @@ static int baseband_xmm_power_on(struct platform_device *device)
pr_debug("%s: register usb host controller\n",
__func__);
modem_power_on = true;
- if (data->hsic_register)
- data->modem.xmm.hsic_device =
- data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n",
__func__);
register_hsic_device = false;
} else {
/* register usb host controller */
- if (data->hsic_register)
- data->modem.xmm.hsic_device =
- data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
/* turn on modem */
pr_debug("%s call baseband_modem_power_on\n", __func__);
- baseband_modem_power_on(data);
+ baseband_modem_power_on(pdata);
}
}
- ret = enable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ ret = enable_irq_wake(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake));
if (ret < 0)
pr_err("%s: enable_irq_wake error\n", __func__);
-
pr_debug("%s }\n", __func__);
return 0;
}
-static int baseband_xmm_power_off(struct platform_device *device)
+static int xmm_power_off(struct platform_device *device)
{
- struct baseband_power_platform_data *data;
+ struct baseband_power_platform_data *pdata =
+ device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
+
int ret;
unsigned long flags;
@@ -208,51 +280,51 @@ static int baseband_xmm_power_off(struct platform_device *device)
pr_err("%s: !device\n", __func__);
return -EINVAL;
}
- data = (struct baseband_power_platform_data *)
- device->dev.platform_data;
- if (!data) {
- pr_err("%s: !data\n", __func__);
+ if (!pdata) {
+ pr_err("%s: !pdata\n", __func__);
return -EINVAL;
}
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
- ret = disable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ ret = disable_irq_wake(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake));
if (ret < 0)
pr_err("%s: disable_irq_wake error\n", __func__);
/* unregister usb host controller */
- if (data->hsic_unregister)
- data->hsic_unregister(data->modem.xmm.hsic_device);
+ if (pdata->hsic_unregister)
+ pdata->hsic_unregister(data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* wait 20 ms */
mdelay(20);
/* drive bb_rst low */
- gpio_set_value(data->modem.xmm.bb_rst, 0);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
mdelay(1);
- spin_lock_irqsave(&xmm_lock, flags);
baseband_xmm_powerstate = BBXMM_PS_UNINIT;
- wakeup_pending = false;
modem_sleep_flag = false;
+ CP_initiated_L2toL0 = false;
+ spin_lock_irqsave(&xmm_lock, flags);
+ wakeup_pending = false;
+ system_suspending = false;
spin_unlock_irqrestore(&xmm_lock, flags);
/* start registration process once again on xmm on */
register_hsic_device = true;
+
+ tegra_baseband_rail_off();
pr_debug("%s }\n", __func__);
return 0;
}
-static ssize_t baseband_xmm_onoff(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t xmm_onoff(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int pwr;
int size;
@@ -288,38 +360,46 @@ static ssize_t baseband_xmm_onoff(struct device *dev,
pr_debug("%s power_onoff=%d\n", __func__, power_onoff);
if (power_onoff == 0)
- baseband_xmm_power_off(device);
+ xmm_power_off(device);
else if (power_onoff == 1)
- baseband_xmm_power_on(device);
+ xmm_power_on(device);
mutex_unlock(&xmm_onoff_mutex);
return count;
}
+static void pm_qos_worker(struct work_struct *work)
+{
+ pr_debug("%s - pm qos CPU back to normal\n", __func__);
+ pm_qos_update_request(&boost_cpu_freq_req,
+ (s32)PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE);
+}
+
static DEVICE_ATTR(xmm_onoff, S_IRUSR | S_IWUSR | S_IRGRP,
- NULL, baseband_xmm_onoff);
+ NULL, xmm_onoff);
void baseband_xmm_set_power_status(unsigned int status)
{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
+ struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
int value = 0;
unsigned long flags;
- pr_debug("%s\n", __func__);
-
if (baseband_xmm_powerstate == status)
return;
-
+ pr_debug("%s\n", __func__);
switch (status) {
case BBXMM_PS_L0:
if (modem_sleep_flag) {
pr_info("%s Resume from L3 without calling resume"
"function\n", __func__);
- baseband_xmm_power_driver_handle_resume(data);
+ xmm_power_driver_handle_resume(data);
}
pr_info("L0\n");
+ baseband_xmm_powerstate = status;
+ if (!wake_lock_active(&wakelock))
+ wake_lock(&wakelock);
value = gpio_get_value(data->modem.xmm.ipc_hsic_active);
pr_debug("before L0 ipc_hsic_active=%d\n", value);
if (!value) {
@@ -330,16 +410,21 @@ void baseband_xmm_set_power_status(unsigned int status)
modem_power_on = false;
baseband_modem_power_on(data);
}
-
- if (!wake_lock_active(&wakelock))
- wake_lock(&wakelock);
-
pr_debug("gpio host active high->\n");
break;
case BBXMM_PS_L2:
pr_info("L2\n");
- wake_unlock(&wakelock);
- modem_sleep_flag = true;
+ baseband_xmm_powerstate = status;
+ spin_lock_irqsave(&xmm_lock, flags);
+ if (wakeup_pending) {
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ xmm_power_L2_resume();
+ } else {
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ if (wake_lock_active(&wakelock))
+ wake_unlock(&wakelock);
+ modem_sleep_flag = true;
+ }
break;
case BBXMM_PS_L3:
if (baseband_xmm_powerstate == BBXMM_PS_L2TOL0) {
@@ -352,6 +437,14 @@ void baseband_xmm_set_power_status(unsigned int status)
}
}
pr_info("L3\n");
+ /* system is going to suspend */
+ if (baseband_xmm_powerstate == BBXMM_PS_L2)
+ tegra_baseband_rail_off();
+
+ baseband_xmm_powerstate = status;
+ spin_lock_irqsave(&xmm_lock, flags);
+ system_suspending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
if (wake_lock_active(&wakelock)) {
pr_info("%s: releasing wakelock before L3\n",
__func__);
@@ -361,140 +454,138 @@ void baseband_xmm_set_power_status(unsigned int status)
pr_debug("gpio host active low->\n");
break;
case BBXMM_PS_L2TOL0:
+ spin_lock_irqsave(&xmm_lock, flags);
+ system_suspending = false;
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
/* do this only from L2 state */
if (baseband_xmm_powerstate == BBXMM_PS_L2) {
baseband_xmm_powerstate = status;
pr_debug("BB XMM POWER STATE = %d\n", status);
- baseband_xmm_power_L2_resume();
+ xmm_power_L2_resume();
}
+ baseband_xmm_powerstate = status;
+ break;
+ case BBXMM_PS_L3TOL0:
+ /* poweron rail for L3 -> L0 (system resume) */
+ pr_debug("L3 -> L0, turning on power rail.\n");
+ tegra_baseband_rail_on();
+ baseband_xmm_powerstate = status;
+ break;
default:
+ baseband_xmm_powerstate = status;
break;
}
- baseband_xmm_powerstate = status;
pr_debug("BB XMM POWER STATE = %d\n", status);
}
EXPORT_SYMBOL_GPL(baseband_xmm_set_power_status);
-irqreturn_t baseband_xmm_power_ipc_ap_wake_irq(int irq, void *dev_id)
+irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id)
{
+ struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
int value;
- value = gpio_get_value(baseband_power_driver_data->
- modem.xmm.ipc_ap_wake);
-
+ value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
pr_debug("%s g(%d), wake_st(%d)\n", __func__, value, ipc_ap_wake_state);
- if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
+ /* modem initialization/bootup part*/
+ if (unlikely(ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY)) {
pr_err("%s - spurious irq\n", __func__);
+ return IRQ_HANDLED;
} else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
if (!value) {
pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - got falling edge\n",
- __func__);
+ " - got falling edge\n", __func__);
/* go to IPC_AP_WAKE_INIT1 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- /* queue work */
queue_work(workqueue, &init1_work);
- } else {
+ } else
pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - wait for falling edge\n",
- __func__);
- }
+ " - wait for falling edge\n", __func__);
+ return IRQ_HANDLED;
} else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
if (!value) {
pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - wait for rising edge\n",
- __func__);
+ " - wait for rising edge\n", __func__);
} else {
pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - got rising edge\n",
- __func__);
+ " - got rising edge\n", __func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
- /* queue work */
queue_work(workqueue, &init2_work);
}
- } else {
- if (!value) {
- pr_debug("%s - falling\n", __func__);
- /* [ver < 1130] gpio protocol falling edge */
- if (modem_ver < XMM_MODEM_VER_1130) {
- pr_debug("gpio host wakeup done <-\n");
- value = gpio_get_value
- (baseband_power_driver_data->
- modem.xmm.ipc_bb_wake);
- if (value) {
- /* Clear the slave wakeup request */
- gpio_set_value
- (baseband_power_driver_data->
- modem.xmm.ipc_bb_wake, 0);
- pr_debug("gpio slave wakeup done ->\n");
- }
- }
- /* [ver >= 1130] gpio protocol falling edge */
- if (modem_ver >= XMM_MODEM_VER_1130) {
- if (baseband_xmm_powerstate == BBXMM_PS_L2) {
- CP_initiated_L2toL0 = true;
- baseband_xmm_set_power_status
- (BBXMM_PS_L2TOL0);
- } else if (baseband_xmm_powerstate ==
- BBXMM_PS_L3) {
- spin_lock(&xmm_lock);
- wakeup_pending = true;
- spin_unlock(&xmm_lock);
- pr_info("CP L3 -> L0\n");
- }
- }
- /* save gpio state */
+ return IRQ_HANDLED;
+ }
+
+ /* modem wakeup part */
+ if (!value) {
+ pr_debug("%s - falling\n", __func__);
+ /* First check it a CP ack or CP wake */
+ value = gpio_get_value(data->modem.xmm.ipc_bb_wake);
+ if (value) {
+ pr_debug("cp ack for bb_wake\n");
ipc_ap_wake_state = IPC_AP_WAKE_L;
+ return IRQ_HANDLED;
+ }
+ spin_lock(&xmm_lock);
+ wakeup_pending = true;
+ if (system_suspending) {
+ spin_unlock(&xmm_lock);
+ pr_info("Set wakeup_pending = 1 in system_"
+ " suspending!!!\n");
} else {
- pr_debug("%s - rising\n", __func__);
- /* [ver >= 1130] gpio protocol rising edge */
- if (modem_ver >= XMM_MODEM_VER_1130) {
- pr_debug("gpio host wakeup done <-\n");
- value = gpio_get_value
- (baseband_power_driver_data->
- modem.xmm.ipc_bb_wake);
- if (value) {
- /* Clear the slave wakeup request */
- gpio_set_value
- (baseband_power_driver_data->
- modem.xmm.ipc_bb_wake, 0);
- pr_debug("gpio slave wakeup done ->\n");
- if (reenable_autosuspend && usbdev) {
- reenable_autosuspend = false;
- queue_work(workqueue,
- &autopm_resume_work);
- }
- }
- if ((baseband_xmm_powerstate ==
- BBXMM_PS_L2TOL0) ||
- (baseband_xmm_powerstate ==
- BBXMM_PS_L3TOL0))
- baseband_xmm_set_power_status(
- BBXMM_PS_L0);
- else
- pr_info("%s:no state"
- "change required\n", __func__);
+ if ((baseband_xmm_powerstate == BBXMM_PS_L3) ||
+ (baseband_xmm_powerstate == BBXMM_PS_L3TOL0)) {
+ spin_unlock(&xmm_lock);
+ pr_info(" CP L3 -> L0\n");
+ } else if (baseband_xmm_powerstate == BBXMM_PS_L2) {
+ CP_initiated_L2toL0 = true;
+ spin_unlock(&xmm_lock);
+ baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
+ } else {
+ CP_initiated_L2toL0 = true;
+ spin_unlock(&xmm_lock);
}
- /* save gpio state */
+ }
+ /* save gpio state */
+ ipc_ap_wake_state = IPC_AP_WAKE_L;
+ } else {
+ pr_debug("%s - rising\n", __func__);
+ value = gpio_get_value(data->modem.xmm.ipc_hsic_active);
+ if (!value) {
+ pr_info("host active low: ignore request\n");
ipc_ap_wake_state = IPC_AP_WAKE_H;
+ return IRQ_HANDLED;
}
+ value = gpio_get_value(data->modem.xmm.ipc_bb_wake);
+ if (value) {
+ /* Clear the slave wakeup request */
+ gpio_set_value(data->modem.xmm.ipc_bb_wake, 0);
+ pr_debug("gpio slave wakeup done ->\n");
+ }
+ if (reenable_autosuspend && usbdev) {
+ reenable_autosuspend = false;
+ queue_work(workqueue, &autopm_resume_work);
+ }
+ modem_sleep_flag = false;
+ baseband_xmm_set_power_status(BBXMM_PS_L0);
+ /* save gpio state */
+ ipc_ap_wake_state = IPC_AP_WAKE_H;
}
return IRQ_HANDLED;
}
-EXPORT_SYMBOL(baseband_xmm_power_ipc_ap_wake_irq);
+EXPORT_SYMBOL(xmm_power_ipc_ap_wake_irq);
-static void baseband_xmm_power_init1_work(struct work_struct *work)
+static void xmm_power_init1_work(struct work_struct *work)
{
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
int value;
pr_debug("%s {\n", __func__);
/* check if IPC_HSIC_ACTIVE high */
- value = gpio_get_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active);
+ value = gpio_get_value(pdata->modem.xmm.ipc_hsic_active);
if (value != 1) {
pr_err("%s - expected IPC_HSIC_ACTIVE high!\n", __func__);
return;
@@ -504,15 +595,13 @@ static void baseband_xmm_power_init1_work(struct work_struct *work)
mdelay(100);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* wait 10 ms */
mdelay(10);
/* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* wait 20 ms */
mdelay(20);
@@ -520,20 +609,20 @@ static void baseband_xmm_power_init1_work(struct work_struct *work)
pr_debug("%s }\n", __func__);
}
-static void baseband_xmm_power_init2_work(struct work_struct *work)
+static void xmm_power_init2_work(struct work_struct *work)
{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
pr_debug("%s\n", __func__);
/* check input */
- if (!data)
+ if (!pdata)
return;
/* register usb host controller only once */
if (register_hsic_device) {
- if (data->hsic_register)
- data->modem.xmm.hsic_device = data->hsic_register();
+ if (pdata->hsic_register)
+ xmm_power_drv_data.hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n", __func__);
register_hsic_device = false;
@@ -541,7 +630,7 @@ static void baseband_xmm_power_init2_work(struct work_struct *work)
}
-static void baseband_xmm_power_autopm_resume(struct work_struct *work)
+static void xmm_power_autopm_resume(struct work_struct *work)
{
struct usb_interface *intf;
@@ -549,26 +638,37 @@ static void baseband_xmm_power_autopm_resume(struct work_struct *work)
if (usbdev) {
usb_lock_device(usbdev);
intf = usb_ifnum_to_if(usbdev, 0);
- usb_autopm_get_interface(intf);
- usb_autopm_put_interface(intf);
+ if (!intf) {
+ usb_unlock_device(usbdev);
+ return;
+ }
+ if (usb_autopm_get_interface(intf) == 0)
+ usb_autopm_put_interface(intf);
usb_unlock_device(usbdev);
}
}
/* Do the work for AP/CP initiated L2->L0 */
-static void baseband_xmm_power_L2_resume(void)
+static void xmm_power_L2_resume(void)
{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
int value;
- int delay = 1000; /* maxmum delay in msec */
+ int delay = 10000; /* maxmum delay in msec */
+ unsigned long flags;
pr_debug("%s\n", __func__);
- if (!baseband_power_driver_data)
+ if (!pdata)
return;
+ /* claim the wakelock here to avoid any system suspend */
+ if (!wake_lock_active(&wakelock))
+ wake_lock(&wakelock);
modem_sleep_flag = false;
+ spin_lock_irqsave(&xmm_lock, flags);
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
if (CP_initiated_L2toL0) {
pr_info("CP L2->L0\n");
@@ -577,22 +677,29 @@ static void baseband_xmm_power_L2_resume(void)
} else {
/* set the slave wakeup request */
pr_info("AP L2->L0\n");
- gpio_set_value(data->modem.xmm.ipc_bb_wake, 1);
- pr_debug("waiting for host wakeup from CP...\n");
- do {
- mdelay(1);
- value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
- delay--;
- } while ((value) && (delay));
- if (delay)
- pr_debug("gpio host wakeup low <-\n");
- else
- pr_info("!!AP L2->L0 Failed\n");
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
+ if (value) {
+ pr_debug("waiting for host wakeup from CP...\n");
+ /* wake bb */
+ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1);
+ do {
+ mdelay(1);
+ value = gpio_get_value(
+ pdata->modem.xmm.ipc_ap_wake);
+ delay--;
+ } while ((value) && (delay));
+ if (delay)
+ pr_debug("gpio host wakeup low <-\n");
+ else
+ pr_info("!!AP L2->L0 Failed\n");
+ } else {
+ pr_info("CP already ready\n");
+ }
}
}
/* Do the work for CP initiated L2->L0 */
-static void baseband_xmm_power_L2_resume_work(struct work_struct *work)
+static void xmm_power_L2_resume_work(struct work_struct *work)
{
struct usb_interface *intf;
@@ -609,119 +716,77 @@ static void baseband_xmm_power_L2_resume_work(struct work_struct *work)
pr_debug("} %s\n", __func__);
}
-static void baseband_xmm_power_reset_on(void)
+static void xmm_power_reset_on(struct baseband_power_platform_data *pdata)
{
/* reset / power on sequence */
- mdelay(40);
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_rst, 1);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
+ msleep(40);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 1);
mdelay(1);
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_on, 1);
- udelay(40);
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_on, 0);
+ gpio_set_value(pdata->modem.xmm.bb_on, 1);
+ udelay(70);
+ gpio_set_value(pdata->modem.xmm.bb_on, 0);
}
-static struct baseband_xmm_power_work_t *baseband_xmm_power_work;
-static void baseband_xmm_power_work_func(struct work_struct *work)
+static void xmm_power_work_func(struct work_struct *work)
{
- struct baseband_xmm_power_work_t *bbxmm_work
- = (struct baseband_xmm_power_work_t *) work;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
pr_debug("%s\n", __func__);
- switch (bbxmm_work->state) {
+ switch (data->state) {
case BBXMM_WORK_UNINIT:
pr_debug("BBXMM_WORK_UNINIT\n");
break;
case BBXMM_WORK_INIT:
pr_debug("BBXMM_WORK_INIT\n");
/* go to next state */
- bbxmm_work->state = (modem_flash && !modem_pm)
+ data->state = (modem_flash && !modem_pm)
? BBXMM_WORK_INIT_FLASH_STEP1
: (modem_flash && modem_pm)
? BBXMM_WORK_INIT_FLASH_PM_STEP1
: (!modem_flash && modem_pm)
? BBXMM_WORK_INIT_FLASHLESS_PM_STEP1
: BBXMM_WORK_UNINIT;
- pr_debug("Go to next state %d\n", bbxmm_work->state);
+ pr_debug("Go to next state %d\n", data->state);
queue_work(workqueue, work);
break;
case BBXMM_WORK_INIT_FLASH_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n");
/* register usb host controller */
pr_debug("%s: register usb host controller\n", __func__);
- if (baseband_power_driver_data->hsic_register)
- baseband_power_driver_data->modem.xmm.hsic_device =
- baseband_power_driver_data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n", __func__);
break;
case BBXMM_WORK_INIT_FLASH_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
- /* [modem ver >= 1130] start with IPC_HSIC_ACTIVE low */
- if (modem_ver >= XMM_MODEM_VER_1130) {
- pr_debug("%s: ver > 1130:"
- " ipc_hsic_active -> 0\n", __func__);
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 0);
- }
+ pr_debug("%s: ipc_hsic_active -> 0\n", __func__);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* reset / power on sequence */
- baseband_xmm_power_reset_on();
+ xmm_power_reset_on(pdata);
/* set power status as on */
power_onoff = 1;
- /* optional delay
- * 0 = flashless
- * ==> causes next step to enumerate modem boot rom
- * (058b / 0041)
- * some delay > boot rom timeout
- * ==> causes next step to enumerate modem software
- * (1519 / 0020)
- * (requires modem to be flash version, not flashless
- * version)
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
+
+ /* expecting init2 performs register hsic to enumerate modem
+ * software directly.
*/
- if (enum_delay_ms)
- mdelay(enum_delay_ms);
- /* register usb host controller */
- pr_debug("%s: register usb host controller\n", __func__);
- if (baseband_power_driver_data->hsic_register)
- baseband_power_driver_data->modem.xmm.hsic_device =
- baseband_power_driver_data->hsic_register();
- else
- pr_err("%s: hsic_register is missing\n", __func__);
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1
- : BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- pr_debug("Go to next state %d\n", bbxmm_work->state);
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1\n");
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1\n");
break;
case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n");
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ
- : BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n");
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n");
+ pr_info("%s: flashless is not supported here\n", __func__);
break;
default:
break;
}
-
}
-static void baseband_xmm_device_add_handler(struct usb_device *udev)
+static void xmm_device_add_handler(struct usb_device *udev)
{
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
const struct usb_device_id *id;
@@ -741,7 +806,7 @@ static void baseband_xmm_device_add_handler(struct usb_device *udev)
}
}
-static void baseband_xmm_device_remove_handler(struct usb_device *udev)
+static void xmm_device_remove_handler(struct usb_device *udev)
{
if (usbdev == udev) {
pr_info("Remove device %d <%s %s>\n", udev->devnum,
@@ -756,10 +821,10 @@ static int usb_xmm_notify(struct notifier_block *self, unsigned long action,
{
switch (action) {
case USB_DEVICE_ADD:
- baseband_xmm_device_add_handler(blob);
+ xmm_device_add_handler(blob);
break;
case USB_DEVICE_REMOVE:
- baseband_xmm_device_remove_handler(blob);
+ xmm_device_remove_handler(blob);
break;
}
@@ -771,11 +836,64 @@ static struct notifier_block usb_xmm_nb = {
.notifier_call = usb_xmm_notify,
};
-static int baseband_xmm_power_driver_probe(struct platform_device *device)
+static int xmm_power_pm_notifier_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- device->dev.platform_data;
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
+ unsigned long flags;
+
+ if (!pdata)
+ return NOTIFY_DONE;
+
+ pr_debug("%s: event %ld\n", __func__, event);
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ pr_debug("%s : PM_SUSPEND_PREPARE\n", __func__);
+ if (wake_lock_active(&wakelock)) {
+ pr_info("%s: wakelock was active, aborting suspend\n",
+ __func__);
+ return NOTIFY_STOP;
+ }
+
+ spin_lock_irqsave(&xmm_lock, flags);
+ if (wakeup_pending) {
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ pr_info("%s : XMM busy : Abort system suspend\n",
+ __func__);
+ return NOTIFY_STOP;
+ }
+ system_suspending = true;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ return NOTIFY_OK;
+ case PM_POST_SUSPEND:
+ pr_debug("%s : PM_POST_SUSPEND\n", __func__);
+ spin_lock_irqsave(&xmm_lock, flags);
+ system_suspending = false;
+ if (wakeup_pending &&
+ (baseband_xmm_powerstate == BBXMM_PS_L2)) {
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ pr_info("%s : Service Pending CP wakeup\n", __func__);
+ CP_initiated_L2toL0 = true;
+ baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
+ return NOTIFY_OK;
+ }
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ return NOTIFY_OK;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xmm_power_pm_notifier = {
+ .notifier_call = xmm_power_pm_notifier_event,
+};
+
+
+static int xmm_power_driver_probe(struct platform_device *device)
+{
+ struct baseband_power_platform_data *pdata = device->dev.platform_data;
struct device *dev = &device->dev;
unsigned long flags;
int err;
@@ -784,17 +902,17 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
pr_debug("[XMM] enum_delay_ms=%ld\n", enum_delay_ms);
/* check for platform data */
- if (!data)
+ if (!pdata)
return -ENODEV;
/* check if supported modem */
- if (data->baseband_type != BASEBAND_XMM) {
+ if (pdata->baseband_type != BASEBAND_XMM) {
pr_err("unsuppported modem\n");
return -ENODEV;
}
/* save platform data */
- baseband_power_driver_data = data;
+ xmm_power_drv_data.pdata = pdata;
/* create device file */
err = device_create_file(dev, &dev_attr_xmm_onoff);
@@ -809,20 +927,14 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
/* init spin lock */
spin_lock_init(&xmm_lock);
/* request baseband gpio(s) */
- tegra_baseband_gpios[0].gpio = baseband_power_driver_data
- ->modem.xmm.bb_rst;
- tegra_baseband_gpios[1].gpio = baseband_power_driver_data
- ->modem.xmm.bb_on;
- tegra_baseband_gpios[2].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_bb_wake;
- tegra_baseband_gpios[3].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_ap_wake;
- tegra_baseband_gpios[4].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_hsic_active;
- tegra_baseband_gpios[5].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_hsic_sus_req;
+ tegra_baseband_gpios[0].gpio = pdata->modem.xmm.bb_rst;
+ tegra_baseband_gpios[1].gpio = pdata->modem.xmm.bb_on;
+ tegra_baseband_gpios[2].gpio = pdata->modem.xmm.ipc_bb_wake;
+ tegra_baseband_gpios[3].gpio = pdata->modem.xmm.ipc_ap_wake;
+ tegra_baseband_gpios[4].gpio = pdata->modem.xmm.ipc_hsic_active;
+ tegra_baseband_gpios[5].gpio = pdata->modem.xmm.ipc_hsic_sus_req;
err = gpio_request_array(tegra_baseband_gpios,
- ARRAY_SIZE(tegra_baseband_gpios));
+ ARRAY_SIZE(tegra_baseband_gpios));
if (err < 0) {
pr_err("%s - request gpio(s) failed\n", __func__);
return -ENODEV;
@@ -833,90 +945,76 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
pr_debug("%s: request_irq IPC_AP_WAKE_IRQ\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
err = request_threaded_irq(
- gpio_to_irq(data->modem.xmm.ipc_ap_wake),
- NULL,
- baseband_xmm_power_ipc_ap_wake_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "IPC_AP_WAKE_IRQ",
- NULL);
+ gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
+ NULL, xmm_power_ipc_ap_wake_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "IPC_AP_WAKE_IRQ", NULL);
if (err < 0) {
pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
__func__);
return err;
}
- err = enable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ err = enable_irq_wake(gpio_to_irq(
+ pdata->modem.xmm.ipc_ap_wake));
if (err < 0)
- pr_err("%s: enable_irq_wake error\n", __func__);
- ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
- if (modem_ver >= XMM_MODEM_VER_1130) {
- pr_debug("%s: ver > 1130: AP_WAKE_INIT1\n", __func__);
- /* ver 1130 or later starts in INIT1 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- }
+ pr_err("%s: enable_irq_wake error\n", __func__);
+
+ pr_debug("%s: AP_WAKE_INIT1\n", __func__);
+ /* ver 1130 or later starts in INIT1 state */
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
}
/* init work queue */
- workqueue = create_singlethread_workqueue
- ("baseband_xmm_power_workqueue");
+ workqueue = create_singlethread_workqueue("xmm_power_wq");
if (!workqueue) {
pr_err("cannot create workqueue\n");
- return -1;
+ return -ENOMEM;
}
- baseband_xmm_power_work = (struct baseband_xmm_power_work_t *)
- kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL);
- if (!baseband_xmm_power_work) {
- pr_err("cannot allocate baseband_xmm_power_work\n");
- return -1;
- }
- INIT_WORK((struct work_struct *) baseband_xmm_power_work,
- baseband_xmm_power_work_func);
- baseband_xmm_power_work->state = BBXMM_WORK_INIT;
- queue_work(workqueue,
- (struct work_struct *) baseband_xmm_power_work);
+
+ INIT_WORK(&xmm_power_drv_data.work, xmm_power_work_func);
+ xmm_power_drv_data.state = BBXMM_WORK_INIT;
+ queue_work(workqueue, &xmm_power_drv_data.work);
/* init work objects */
- INIT_WORK(&init1_work, baseband_xmm_power_init1_work);
- INIT_WORK(&init2_work, baseband_xmm_power_init2_work);
- INIT_WORK(&L2_resume_work, baseband_xmm_power_L2_resume_work);
- INIT_WORK(&autopm_resume_work, baseband_xmm_power_autopm_resume);
+ INIT_WORK(&init1_work, xmm_power_init1_work);
+ INIT_WORK(&init2_work, xmm_power_init2_work);
+ INIT_WORK(&L2_resume_work, xmm_power_L2_resume_work);
+ INIT_WORK(&autopm_resume_work, xmm_power_autopm_resume);
/* init state variables */
register_hsic_device = true;
CP_initiated_L2toL0 = false;
- spin_lock_irqsave(&xmm_lock, flags);
baseband_xmm_powerstate = BBXMM_PS_UNINIT;
+ spin_lock_irqsave(&xmm_lock, flags);
wakeup_pending = false;
+ system_suspending = false;
spin_unlock_irqrestore(&xmm_lock, flags);
usb_register_notify(&usb_xmm_nb);
+ register_pm_notifier(&xmm_power_pm_notifier);
pr_debug("%s }\n", __func__);
return 0;
}
-static int baseband_xmm_power_driver_remove(struct platform_device *device)
+static int xmm_power_driver_remove(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- device->dev.platform_data;
+ struct baseband_power_platform_data *pdata = device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
struct device *dev = &device->dev;
pr_debug("%s\n", __func__);
/* check for platform data */
- if (!data)
+ if (!pdata)
return 0;
+ unregister_pm_notifier(&xmm_power_pm_notifier);
usb_unregister_notify(&usb_xmm_nb);
- /* free work structure */
- kfree(baseband_xmm_power_work);
- baseband_xmm_power_work = (struct baseband_xmm_power_work_t *) 0;
-
/* free baseband irq(s) */
if (modem_flash && modem_pm) {
- free_irq(gpio_to_irq(baseband_power_driver_data
- ->modem.xmm.ipc_ap_wake), NULL);
+ free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), NULL);
}
/* free baseband gpio(s) */
@@ -930,23 +1028,23 @@ static int baseband_xmm_power_driver_remove(struct platform_device *device)
device_remove_file(dev, &dev_attr_xmm_onoff);
/* unregister usb host controller */
- if (data->hsic_unregister)
- data->hsic_unregister(data->modem.xmm.hsic_device);
+ if (pdata->hsic_unregister)
+ pdata->hsic_unregister(data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
return 0;
}
-static int baseband_xmm_power_driver_handle_resume(
- struct baseband_power_platform_data *data)
+static int xmm_power_driver_handle_resume(
+ struct baseband_power_platform_data *pdata)
{
int value;
int delay = 1000; /* maxmum delay in msec */
unsigned long flags;
pr_debug("%s\n", __func__);
- if (!data)
+ if (!pdata)
return 0;
/* check if modem is on */
@@ -956,29 +1054,30 @@ static int baseband_xmm_power_driver_handle_resume(
}
modem_sleep_flag = false;
+ spin_lock_irqsave(&xmm_lock, flags);
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
/* L3->L0 */
baseband_xmm_set_power_status(BBXMM_PS_L3TOL0);
- value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
if (value) {
pr_info("AP L3 -> L0\n");
- /* wake bb */
- gpio_set_value(data->modem.xmm.ipc_bb_wake, 1);
-
pr_debug("waiting for host wakeup...\n");
+ /* wake bb */
+ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1);
do {
mdelay(1);
- value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
delay--;
} while ((value) && (delay));
if (delay)
pr_debug("gpio host wakeup low <-\n");
+ else
+ pr_info("!!AP L3->L0 Failed\n");
+
} else {
pr_info("CP L3 -> L0\n");
- spin_lock_irqsave(&xmm_lock, flags);
- /* Clear wakeup pending flag */
- wakeup_pending = false;
- spin_unlock_irqrestore(&xmm_lock, flags);
}
reenable_autosuspend = true;
@@ -986,32 +1085,32 @@ static int baseband_xmm_power_driver_handle_resume(
}
+
#ifdef CONFIG_PM
-static int baseband_xmm_power_driver_suspend(struct device *dev)
+static int xmm_power_driver_suspend(struct device *dev)
{
pr_debug("%s\n", __func__);
return 0;
}
-static int baseband_xmm_power_driver_resume(struct device *dev)
+static int xmm_power_driver_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- pdev->dev.platform_data;
+ struct baseband_power_platform_data *pdata = pdev->dev.platform_data;
pr_debug("%s\n", __func__);
- baseband_xmm_power_driver_handle_resume(data);
+ xmm_power_driver_handle_resume(pdata);
return 0;
}
-static int baseband_xmm_power_suspend_noirq(struct device *dev)
+static int xmm_power_suspend_noirq(struct device *dev)
{
unsigned long flags;
pr_debug("%s\n", __func__);
spin_lock_irqsave(&xmm_lock, flags);
+ system_suspending = false;
if (wakeup_pending) {
wakeup_pending = false;
spin_unlock_irqrestore(&xmm_lock, flags);
@@ -1022,42 +1121,62 @@ static int baseband_xmm_power_suspend_noirq(struct device *dev)
return 0;
}
-static int baseband_xmm_power_resume_noirq(struct device *dev)
+static int xmm_power_resume_noirq(struct device *dev)
{
pr_debug("%s\n", __func__);
return 0;
}
-static const struct dev_pm_ops baseband_xmm_power_dev_pm_ops = {
- .suspend_noirq = baseband_xmm_power_suspend_noirq,
- .resume_noirq = baseband_xmm_power_resume_noirq,
- .suspend = baseband_xmm_power_driver_suspend,
- .resume = baseband_xmm_power_driver_resume,
+static const struct dev_pm_ops xmm_power_dev_pm_ops = {
+ .suspend_noirq = xmm_power_suspend_noirq,
+ .resume_noirq = xmm_power_resume_noirq,
+ .suspend = xmm_power_driver_suspend,
+ .resume = xmm_power_driver_resume,
};
#endif
+static void xmm_power_driver_shutdown(struct platform_device *device)
+{
+ struct baseband_power_platform_data *pdata = device->dev.platform_data;
+
+ pr_debug("%s\n", __func__);
+ disable_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake));
+ /* bb_on is already down, to make sure set 0 again */
+ gpio_set_value(pdata->modem.xmm.bb_on, 0);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
+ return;
+}
+
static struct platform_driver baseband_power_driver = {
- .probe = baseband_xmm_power_driver_probe,
- .remove = baseband_xmm_power_driver_remove,
+ .probe = xmm_power_driver_probe,
+ .remove = xmm_power_driver_remove,
+ .shutdown = xmm_power_driver_shutdown,
.driver = {
.name = "baseband_xmm_power",
#ifdef CONFIG_PM
- .pm = &baseband_xmm_power_dev_pm_ops,
+ .pm = &xmm_power_dev_pm_ops,
#endif
},
};
-static int __init baseband_xmm_power_init(void)
+static int __init xmm_power_init(void)
{
pr_debug("%s\n", __func__);
+
+ INIT_DELAYED_WORK(&pm_qos_work, pm_qos_worker);
+ pm_qos_add_request(&boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
+ (s32)PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE);
+
return platform_driver_register(&baseband_power_driver);
}
-static void __exit baseband_xmm_power_exit(void)
+static void __exit xmm_power_exit(void)
{
pr_debug("%s\n", __func__);
platform_driver_unregister(&baseband_power_driver);
+
+ pm_qos_remove_request(&boost_cpu_freq_req);
}
-module_init(baseband_xmm_power_init)
-module_exit(baseband_xmm_power_exit)
+module_init(xmm_power_init)
+module_exit(xmm_power_exit)
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.h b/arch/arm/mach-tegra/baseband-xmm-power.h
index 0768ed191b05..1f08e3b6900c 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.h
+++ b/arch/arm/mach-tegra/baseband-xmm-power.h
@@ -71,24 +71,19 @@ enum baseband_xmm_power_work_state_t {
BBXMM_WORK_INIT_FLASH_STEP1,
/* initialize flash (with power management support) modem */
BBXMM_WORK_INIT_FLASH_PM_STEP1,
- BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1,
- BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1,
/* initialize flashless (with power management support) modem */
BBXMM_WORK_INIT_FLASHLESS_PM_STEP1,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4,
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP2,
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP3,
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP4,
};
-struct baseband_xmm_power_work_t {
- /* work structure must be first structure member */
- struct work_struct work;
+struct xmm_power_data {
/* xmm modem state */
enum baseband_xmm_power_work_state_t state;
+ struct baseband_power_platform_data *pdata;
+ struct work_struct work;
+ struct platform_device *hsic_device;
};
enum baseband_xmm_powerstate_t {
@@ -104,8 +99,9 @@ enum baseband_xmm_powerstate_t {
BBXMM_PS_LAST = -1,
};
-irqreturn_t baseband_xmm_power_ipc_ap_wake_irq(int irq, void *dev_id);
+irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id);
void baseband_xmm_set_power_status(unsigned int status);
+extern struct xmm_power_data xmm_power_drv_data;
#endif /* BASREBAND_XMM_POWER_H */
diff --git a/arch/arm/mach-tegra/baseband-xmm-power2.c b/arch/arm/mach-tegra/baseband-xmm-power2.c
index 4295b3958202..3c6285c0a070 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power2.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power2.c
@@ -32,8 +32,6 @@
#include "board.h"
#include "devices.h"
-MODULE_LICENSE("GPL");
-
static unsigned long XYZ = 1000 * 1000000 + 800 * 1000 + 500;
module_param(modem_ver, ulong, 0644);
@@ -49,9 +47,8 @@ module_param(XYZ, ulong, 0644);
MODULE_PARM_DESC(XYZ,
"baseband xmm power2 - timing parameters X/Y/Z delay in ms");
-static struct baseband_power_platform_data *baseband_power2_driver_data;
static struct workqueue_struct *workqueue;
-static struct baseband_xmm_power_work_t *baseband_xmm_power2_work;
+static bool free_ipc_ap_wake_irq;
static enum {
IPC_AP_WAKE_UNINIT,
@@ -62,105 +59,37 @@ static enum {
IPC_AP_WAKE_H,
} ipc_ap_wake_state;
-static irqreturn_t baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2
- (int irq, void *dev_id)
-{
- int value;
-
- pr_debug("%s\n", __func__);
-
- /* check for platform data */
- if (!baseband_power2_driver_data)
- return IRQ_HANDLED;
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake);
-
- /* IPC_AP_WAKE state machine */
- if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
- pr_err("%s - spurious irq\n", __func__);
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
- if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - got falling edge\n",
- __func__);
- /* go to IPC_AP_WAKE_INIT1 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- /* queue work */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
- } else {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - wait for falling edge\n",
- __func__);
- }
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
- if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - wait for rising edge\n",
- __func__);
- } else {
- pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - got rising edge\n",
- __func__);
- /* go to IPC_AP_WAKE_INIT2 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
- /* queue work */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
- }
- } else {
- if (!value) {
- pr_debug("%s - falling\n", __func__);
- ipc_ap_wake_state = IPC_AP_WAKE_L;
- } else {
- pr_debug("%s - rising\n", __func__);
- ipc_ap_wake_state = IPC_AP_WAKE_H;
- }
- return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id);
- }
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2
- (int irq, void *dev_id)
+static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
{
int value;
+ struct xmm_power_data *data = dev_id;
+ struct baseband_power_platform_data *pdata = data->pdata;
pr_debug("%s\n", __func__);
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!pdata)
return IRQ_HANDLED;
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake);
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
/* IPC_AP_WAKE state machine */
- if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
+ if (unlikely(ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY))
pr_err("%s - spurious irq\n", __func__);
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
+ else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - got falling edge\n",
+ pr_debug("%s: IPC_AP_WAKE_INIT1 got falling edge\n",
__func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
/* queue work */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
- } else {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - wait for falling edge\n",
- __func__);
- }
+ data->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP2;
+ queue_work(workqueue, &data->work);
+ } else
+ pr_debug("%s: IPC_AP_WAKE_INIT1"
+ " wait for falling edge\n", __func__);
} else {
if (!value) {
pr_debug("%s - falling\n", __func__);
@@ -169,260 +98,154 @@ static irqreturn_t baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2
pr_debug("%s - rising\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_H;
}
- return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id);
+ return xmm_power_ipc_ap_wake_irq(irq, dev_id);
}
return IRQ_HANDLED;
}
-static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step1
- (struct work_struct *work)
-{
- int value;
-
- pr_debug("%s {\n", __func__);
-
- /* check for platform data */
- if (!baseband_power2_driver_data)
- return;
-
- /* check if IPC_HSIC_ACTIVE high */
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active);
- if (value != 1) {
- pr_err("%s - expected IPC_HSIC_ACTIVE high!\n", __func__);
- return;
- }
-
- /* wait 30 ms */
- mdelay(30);
-
- /* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
-
- pr_debug("%s }\n", __func__);
-}
-
-static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step2
- (struct work_struct *work)
-{
- int value;
-
- pr_debug("%s {\n", __func__);
-
- /* check for platform data */
- if (!baseband_power2_driver_data)
- return;
-
- /* check if IPC_HSIC_ACTIVE low */
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active);
- if (value != 0) {
- pr_err("%s - expected IPC_HSIC_ACTIVE low!\n", __func__);
- return;
- }
-
- /* wait 1 ms */
- mdelay(1);
-
- /* unregister usb host controller */
- if (baseband_power2_driver_data->hsic_unregister)
- baseband_power2_driver_data->hsic_unregister(
- baseband_power2_driver_data->modem.xmm.hsic_device);
- else
- pr_err("%s: hsic_unregister is missing\n", __func__);
-
- /* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
-
- /* wait 20 ms */
- mdelay(20);
-
- /* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
-
- /* wait 20 ms */
- mdelay(20);
-
- /* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
-
- pr_debug("%s }\n", __func__);
-}
-
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step1
- (struct work_struct *work)
+static void xmm_power2_step1(struct work_struct *work)
{
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int X = XYZ / 1000000;
- int Y = XYZ / 1000 - X * 1000;
- int Z = XYZ % 1000;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!pdata)
return;
/* unregister usb host controller */
- if (baseband_power2_driver_data->hsic_unregister)
- baseband_power2_driver_data->hsic_unregister(
- baseband_power2_driver_data->modem.xmm.hsic_device);
+ if (pdata->hsic_unregister)
+ pdata->hsic_unregister(data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
/* wait X ms */
- mdelay(X);
+ msleep(X);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
pr_info("%s }\n", __func__);
}
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step2
- (struct work_struct *work)
+static void xmm_power2_step2(struct work_struct *work)
{
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int X = XYZ / 1000000;
int Y = XYZ / 1000 - X * 1000;
int Z = XYZ % 1000;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data || !pdata)
return;
/* wait Y ms */
- mdelay(Y);
+ msleep(Y);
/* register usb host controller */
- if (baseband_power2_driver_data->hsic_register)
- baseband_power2_driver_data->modem.xmm.hsic_device =
- baseband_power2_driver_data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n", __func__);
/* wait Z ms */
- mdelay(Z);
+ msleep(Z);
/* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* queue work function to check if enumeration succeeded */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
+ data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP3;
+ queue_work(workqueue, &data->work);
pr_info("%s }\n", __func__);
}
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step3
- (struct work_struct *work)
+static void xmm_power2_step3(struct work_struct *work)
{
- int X = XYZ / 1000000;
- int Y = XYZ / 1000 - X * 1000;
- int Z = XYZ % 1000;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int enum_success = 0;
+ mm_segment_t oldfs;
+ struct file *filp;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data || !pdata)
return;
- /* wait 500 ms */
- mdelay(500);
+ /* wait 1 sec */
+ msleep(1000);
/* check if enumeration succeeded */
- {
- mm_segment_t oldfs;
- struct file *filp;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- filp = filp_open("/dev/ttyACM0",
- O_RDONLY, 0);
- if (IS_ERR(filp) || (filp == NULL)) {
- pr_err("/dev/ttyACM0 %ld\n",
- PTR_ERR(filp));
- } else {
- filp_close(filp, NULL);
- enum_success = 1;
- }
- set_fs(oldfs);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open("/dev/ttyACM0", O_RDONLY, 0);
+ if (IS_ERR(filp) || (filp == NULL))
+ pr_err("failed to open /dev/ttyACM0 %ld\n", PTR_ERR(filp));
+ else {
+ filp_close(filp, NULL);
+ enum_success = 1;
}
+ set_fs(oldfs);
/* if enumeration failed, attempt recovery pulse */
if (!enum_success) {
pr_info("attempting recovery pulse...\n");
/* wait 20 ms */
- mdelay(20);
+ msleep(20);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* wait 20 ms */
- mdelay(20);
+ msleep(20);
/* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* check if recovery pulse worked */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
+ data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP4;
+ queue_work(workqueue, &data->work);
}
pr_info("%s }\n", __func__);
}
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step4
- (struct work_struct *work)
+static void xmm_power2_step4(struct work_struct *work)
{
- int X = XYZ / 1000000;
- int Y = XYZ / 1000 - X * 1000;
- int Z = XYZ % 1000;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ mm_segment_t oldfs;
+ struct file *filp;
int enum_success = 0;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data)
return;
/* wait 500 ms */
- mdelay(500);
+ msleep(500);
/* check if enumeration succeeded */
- {
- mm_segment_t oldfs;
- struct file *filp;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- filp = filp_open("/dev/ttyACM0",
- O_RDONLY, 0);
- if (IS_ERR(filp) || (filp == NULL)) {
- pr_err("open /dev/ttyACM0 failed %ld\n",
- PTR_ERR(filp));
- } else {
- filp_close(filp, NULL);
- enum_success = 1;
- }
- set_fs(oldfs);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open("/dev/ttyACM0", O_RDONLY, 0);
+ if (IS_ERR(filp) || (filp == NULL))
+ pr_err("failed to open /dev/ttyACM0 %ld\n", PTR_ERR(filp));
+ else {
+ filp_close(filp, NULL);
+ enum_success = 1;
}
+ set_fs(oldfs);
/* if recovery pulse did not fix enumeration, retry from beginning */
if (!enum_success) {
@@ -438,34 +261,31 @@ static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step4
retry);
--retry;
ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
+ data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP1;
+ queue_work(workqueue, &data->work);
}
}
pr_info("%s }\n", __func__);
}
-static int free_ipc_ap_wake_irq;
-
-static void baseband_xmm_power2_work_func(struct work_struct *work)
+static void xmm_power2_work_func(struct work_struct *work)
{
- struct baseband_xmm_power_work_t *bbxmm_work
- = (struct baseband_xmm_power_work_t *) work;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int err;
- pr_debug("%s bbxmm_work->state=%d\n", __func__, bbxmm_work->state);
+ pr_debug("%s pdata->state=%d\n", __func__, data->state);
- switch (bbxmm_work->state) {
+ switch (data->state) {
case BBXMM_WORK_UNINIT:
pr_debug("BBXMM_WORK_UNINIT\n");
/* free baseband irq(s) */
if (free_ipc_ap_wake_irq) {
- free_irq(gpio_to_irq(baseband_power2_driver_data
- ->modem.xmm.ipc_ap_wake), NULL);
- free_ipc_ap_wake_irq = 0;
+ free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
+ data);
+ free_ipc_ap_wake_irq = false;
}
break;
case BBXMM_WORK_INIT:
@@ -473,24 +293,20 @@ static void baseband_xmm_power2_work_func(struct work_struct *work)
/* request baseband irq(s) */
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
err = request_threaded_irq(
- gpio_to_irq(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake),
- NULL,
- (modem_ver < XMM_MODEM_VER_1130)
- ? baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2
- : baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "BBXMM_POWER2_IPC_AP_WAKE_IRQ",
- NULL);
+ gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
+ NULL, xmm_power2_ipc_ap_wake_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "xmm_power2_ipc_ap_wake_irq", data);
if (err < 0) {
pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
__func__);
return;
}
- free_ipc_ap_wake_irq = 1;
+ free_ipc_ap_wake_irq = true;
ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
+
/* go to next state */
- bbxmm_work->state = (modem_flash && !modem_pm)
+ data->state = (modem_flash && !modem_pm)
? BBXMM_WORK_INIT_FLASH_STEP1
: (modem_flash && modem_pm)
? BBXMM_WORK_INIT_FLASH_PM_STEP1
@@ -501,130 +317,93 @@ static void baseband_xmm_power2_work_func(struct work_struct *work)
break;
case BBXMM_WORK_INIT_FLASH_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n");
+ pr_info("%s: flashed modem is not supported here\n", __func__);
break;
case BBXMM_WORK_INIT_FLASH_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1
- : BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1\n");
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1\n");
+ pr_info("%s: flashed modem is not supported here\n", __func__);
break;
case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1:
+ /* start flashless modem enum process */
pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n");
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ
- : BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ"
- " - waiting for IPC_AP_WAKE_IRQ to trigger step1\n");
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n");
- baseband_xmm_power2_flashless_pm_ver_lt_1130_step1(work);
+ xmm_power2_step1(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2\n");
- baseband_xmm_power2_flashless_pm_ver_lt_1130_step2(work);
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP2:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP2\n");
+ xmm_power2_step2(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step1(work);
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP3:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP3\n");
+ xmm_power2_step3(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step2(work);
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP4:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP4\n");
+ xmm_power2_step4(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step3(work);
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step4(work);
+ default:
break;
}
-
}
-static int baseband_xmm_power2_driver_probe(struct platform_device *device)
+static int xmm_power2_probe(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- device->dev.platform_data;
-
pr_debug("%s\n", __func__);
+ if (!device->dev.platform_data) {
+ pr_err("%s: no platform data found\n", __func__);
+ return -ENOMEM;
+ }
- /* save platform data */
- baseband_power2_driver_data = data;
+ xmm_power_drv_data.pdata = device->dev.platform_data;
- /* init work queue */
+ /* create workqueue */
pr_debug("%s: init work queue\n", __func__);
- workqueue = create_singlethread_workqueue
- ("baseband_xmm_power2_workqueue");
- if (!workqueue) {
- pr_err("cannot create workqueue\n");
- return -1;
- }
- baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *)
- kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL);
- if (!baseband_xmm_power2_work) {
- pr_err("cannot allocate baseband_xmm_power2_work\n");
- return -1;
+ workqueue = create_singlethread_workqueue("xmm_power2_wq");
+ if (unlikely(!workqueue)) {
+ pr_err("%s: cannot create workqueue\n", __func__);
+ return -ENOMEM;
}
+
+ /* init work */
pr_debug("%s: BBXMM_WORK_INIT\n", __func__);
- INIT_WORK((struct work_struct *) baseband_xmm_power2_work,
- baseband_xmm_power2_work_func);
- baseband_xmm_power2_work->state = BBXMM_WORK_INIT;
- queue_work(workqueue,
- (struct work_struct *) baseband_xmm_power2_work);
+ INIT_WORK(&xmm_power_drv_data.work, xmm_power2_work_func);
+ xmm_power_drv_data.state = BBXMM_WORK_INIT;
+ queue_work(workqueue, &xmm_power_drv_data.work);
+
return 0;
}
-static int baseband_xmm_power2_driver_remove(struct platform_device *device)
+static int xmm_power2_remove(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *pdata =
device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
pr_debug("%s\n", __func__);
/* check for platform data */
if (!data)
- return 0;
-
- /* free irq */
- if (free_ipc_ap_wake_irq) {
- free_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL);
- free_ipc_ap_wake_irq = 0;
- }
+ return -ENODEV;
- /* free work structure */
+ /* free work queue */
if (workqueue) {
- cancel_work_sync(baseband_xmm_power2_work);
+ cancel_work_sync(&data->work);
destroy_workqueue(workqueue);
}
- kfree(baseband_xmm_power2_work);
- baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *) 0;
+
+ /* free irq */
+ if (free_ipc_ap_wake_irq) {
+ free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), data);
+ free_ipc_ap_wake_irq = false;
+ }
return 0;
}
#ifdef CONFIG_PM
-static int baseband_xmm_power2_driver_suspend(struct platform_device *device,
+static int xmm_power2_suspend(struct platform_device *device,
pm_message_t state)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *data =
device->dev.platform_data;
pr_debug("%s - nop\n", __func__);
@@ -636,10 +415,9 @@ static int baseband_xmm_power2_driver_suspend(struct platform_device *device,
return 0;
}
-static int baseband_xmm_power2_driver_resume(struct platform_device *device)
+static int xmm_power2_resume(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *data =
device->dev.platform_data;
pr_debug("%s - nop\n", __func__);
@@ -653,29 +431,32 @@ static int baseband_xmm_power2_driver_resume(struct platform_device *device)
#endif
static struct platform_driver baseband_power2_driver = {
- .probe = baseband_xmm_power2_driver_probe,
- .remove = baseband_xmm_power2_driver_remove,
+ .probe = xmm_power2_probe,
+ .remove = xmm_power2_remove,
#ifdef CONFIG_PM
- .suspend = baseband_xmm_power2_driver_suspend,
- .resume = baseband_xmm_power2_driver_resume,
+ .suspend = xmm_power2_suspend,
+ .resume = xmm_power2_resume,
#endif
.driver = {
.name = "baseband_xmm_power2",
},
};
-static int __init baseband_xmm_power2_init(void)
+static int __init xmm_power2_init(void)
{
pr_debug("%s\n", __func__);
return platform_driver_register(&baseband_power2_driver);
}
-static void __exit baseband_xmm_power2_exit(void)
+static void __exit xmm_power2_exit(void)
{
pr_debug("%s\n", __func__);
+
platform_driver_unregister(&baseband_power2_driver);
}
-module_init(baseband_xmm_power2_init)
-module_exit(baseband_xmm_power2_exit)
+module_init(xmm_power2_init)
+module_exit(xmm_power2_exit)
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-tegra/board-aruba-panel.c b/arch/arm/mach-tegra/board-aruba-panel.c
index b014326fc91b..0e24a4375c99 100644
--- a/arch/arm/mach-tegra/board-aruba-panel.c
+++ b/arch/arm/mach-tegra/board-aruba-panel.c
@@ -26,7 +26,7 @@
#include <linux/platform_device.h>
#include <linux/pwm_backlight.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
diff --git a/arch/arm/mach-tegra/board-cardhu-kbc.c b/arch/arm/mach-tegra/board-cardhu-kbc.c
index 3bf0a3b864fc..16e83bbb03f8 100644
--- a/arch/arm/mach-tegra/board-cardhu-kbc.c
+++ b/arch/arm/mach-tegra/board-cardhu-kbc.c
@@ -174,7 +174,8 @@ static struct gpio_keys_button cardhu_keys_e1291_a04[] = {
[3] = GPIO_KEY(KEY_SEARCH, PQ3, 0),
[4] = GPIO_KEY(KEY_BACK, PQ0, 0),
[5] = GPIO_KEY(KEY_MENU, PQ1, 0),
- [6] = GPIO_IKEY(KEY_POWER, TPS6591X_IRQ_BASE + TPS6591X_INT_PWRON, 1, 100),
+ [6] = GPIO_KEY(KEY_RESERVED, PV0, 1),
+ [7] = GPIO_IKEY(KEY_POWER, TPS6591X_IRQ_BASE + TPS6591X_INT_PWRON, 1, 100),
};
static struct gpio_keys_platform_data cardhu_keys_e1291_pdata = {
@@ -200,7 +201,7 @@ static struct gpio_keys_button cardhu_pm298_int_keys[] = {
};
static struct gpio_keys_button cardhu_pm299_int_keys[] = {
- [0] = GPIO_IKEY(KEY_POWER, RICOH583_IRQ_BASE + RICOH583_IRQ_ONKEY, 1, 100),
+ [0] = GPIO_KEY(KEY_POWER, PV0, 1),
};
static struct gpio_keys_platform_data cardhu_int_keys_pdata = {
@@ -230,6 +231,7 @@ int __init cardhu_keys_init(void)
(board_info.board_id == BOARD_E1257) ||
(board_info.board_id == BOARD_PM305) ||
(board_info.board_id == BOARD_PM311) ||
+ (board_info.board_id == BOARD_PM267) ||
(board_info.board_id == BOARD_PM269)))
return 0;
@@ -290,6 +292,7 @@ int __init cardhu_keys_init(void)
(board_info.board_id == BOARD_E1186) ||
(board_info.board_id == BOARD_PM305) ||
(board_info.board_id == BOARD_PM311) ||
+ (board_info.board_id == BOARD_PM267) ||
(board_info.board_id == BOARD_PM269)) {
if (get_tegra_image_type() == rck_image)
cardhu_int_keys[0].code = KEY_ENTER;
diff --git a/arch/arm/mach-tegra/board-cardhu-memory.c b/arch/arm/mach-tegra/board-cardhu-memory.c
index 0cd9e0066668..6eb86335c7f7 100644
--- a/arch/arm/mach-tegra/board-cardhu-memory.c
+++ b/arch/arm/mach-tegra/board-cardhu-memory.c
@@ -2539,6 +2539,246 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
},
{
0x32, /* Rev 3.2 */
+ 400000, /* SDRAM frequency */
+ {
+ 0x00000012, /* EMC_RC */
+ 0x00000066, /* EMC_RFC */
+ 0x0000000c, /* EMC_RAS */
+ 0x00000004, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000008, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000a, /* EMC_W2P */
+ 0x00000004, /* EMC_RD_RCD */
+ 0x00000004, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000006, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x0000000a, /* EMC_QSAFE */
+ 0x0000000d, /* EMC_RDV */
+ 0x00000bf0, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000002fc, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000008, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000008, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x0000006c, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000c, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000c30, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x001d0084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00038000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0158000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800018c8, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */
+ 0x7086120a, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff89, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000521, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200000, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 667000, /* SDRAM frequency */
+ {
+ 0x00000023, /* EMC_RC */
+ 0x000000df, /* EMC_RFC */
+ 0x00000019, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x00001419, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000005a6, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000010, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000e, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x000000e9, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000005, /* EMC_TCKE */
+ 0x00000017, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x000016da, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0080191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00000008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x00df000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80002d93, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000b, /* MC_EMEM_ARB_CFG */
+ 0x80000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000012, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d12, /* MC_EMEM_ARB_DA_COVERS */
+ 0x73cc2213, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
750000, /* SDRAM frequency */
{
0x00000023, /* EMC_RC */
@@ -2657,6 +2897,126 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x80200018, /* Mode Register 2 */
0x00000000, /* EMC_CFG.DYN_SELF_REF */
},
+ {
+ 0x32, /* Rev 3.2 */
+ 800000, /* SDRAM frequency */
+ {
+ 0x00000025, /* EMC_RC */
+ 0x000000ce, /* EMC_RFC */
+ 0x0000001a, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000012, /* EMC_RDV */
+ 0x00001820, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000012, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000f, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x000000d8, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000005, /* EMC_TCKE */
+ 0x00000018, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x00001860, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0070191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0000c008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ0 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ1 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ2 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x00f0000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000013, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */
+ 0x712c2414, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
};
static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
diff --git a/arch/arm/mach-tegra/board-cardhu-panel.c b/arch/arm/mach-tegra/board-cardhu-panel.c
index 80adfc030921..4899dee38042 100644
--- a/arch/arm/mach-tegra/board-cardhu-panel.c
+++ b/arch/arm/mach-tegra/board-cardhu-panel.c
@@ -30,7 +30,7 @@
#include <linux/pwm_backlight.h>
#include <asm/atomic.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -707,8 +707,8 @@ static struct tegra_fb_data cardhu_fb_data = {
static struct tegra_fb_data cardhu_hdmi_fb_data = {
.win = 0,
- .xres = 1366,
- .yres = 768,
+ .xres = 640,
+ .yres = 480,
.bits_per_pixel = 32,
.flags = TEGRA_FB_FLIP_ON_PROBE,
};
@@ -734,7 +734,7 @@ static struct tegra_dc_out cardhu_disp2_out = {
};
static struct tegra_dc_platform_data cardhu_disp2_pdata = {
- .flags = 0,
+ .flags = TEGRA_DC_FLAG_ENABLED,
.default_out = &cardhu_disp2_out,
.fb = &cardhu_hdmi_fb_data,
.emc_clk_rate = 300000000,
@@ -1301,6 +1301,11 @@ int __init cardhu_panel_init(void)
IORESOURCE_MEM, "fbmem");
res->start = tegra_fb2_start;
res->end = tegra_fb2_start + tegra_fb2_size - 1;
+
+ /* Copy the bootloader fb to the fb2. */
+ tegra_move_framebuffer(tegra_fb2_start, tegra_bootloader_fb_start,
+ min(tegra_fb2_size, tegra_bootloader_fb_size));
+
if (!err)
err = nvhost_device_register(&cardhu_disp2_device);
#endif
diff --git a/arch/arm/mach-tegra/board-cardhu-pinmux.c b/arch/arm/mach-tegra/board-cardhu-pinmux.c
index 112fcc976715..fd0a6ae34ffc 100644
--- a/arch/arm/mach-tegra/board-cardhu-pinmux.c
+++ b/arch/arm/mach-tegra/board-cardhu-pinmux.c
@@ -442,8 +442,8 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_cardhu[] = {
/* Power rails GPIO */
DEFAULT_PINMUX(GMI_CS2_N, NAND, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GMI_RST_N, RSVD3, PULL_UP, TRISTATE, INPUT),
- DEFAULT_PINMUX(GMI_AD15, NAND, PULL_UP, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GMI_RST_N, RSVD3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD15, NAND, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_CS0_N, GMI, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_CS1_N, GMI, PULL_UP, TRISTATE, INPUT),
@@ -466,8 +466,8 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_cardhu_a03[] = {
/* Power rails GPIO */
DEFAULT_PINMUX(PEX_L0_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(PEX_L0_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD3, PULL_UP, TRISTATE, INPUT),
- DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD3, PULL_UP, TRISTATE, INPUT),
+ DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD3, PULL_UP, NORMAL, INPUT),
};
static __initdata struct tegra_pingroup_config cardhu_pinmux_e1291_a04[] = {
diff --git a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
index afff346babeb..0305ee702cbd 100644
--- a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
+++ b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
@@ -461,13 +461,13 @@ static struct regulator_consumer_supply fixed_reg_en_vdd_pnl1_supply[] = {
/* CAM1_LDO_EN from AP GPIO KB_ROW6 R06*/
static struct regulator_consumer_supply fixed_reg_cam1_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam1", NULL),
- REGULATOR_SUPPLY("vdd", "6-0072"),
+ REGULATOR_SUPPLY("avdd", "6-0072"),
};
/* CAM2_LDO_EN from AP GPIO KB_ROW7 R07*/
static struct regulator_consumer_supply fixed_reg_cam2_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam2", NULL),
- REGULATOR_SUPPLY("vdd", "7-0072"),
+ REGULATOR_SUPPLY("avdd", "7-0072"),
};
/* CAM3_LDO_EN from AP GPIO KB_ROW8 S00*/
@@ -505,8 +505,8 @@ static struct regulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = {
REGULATOR_SUPPLY("vdd_1v8_cam1", NULL),
REGULATOR_SUPPLY("vdd_1v8_cam2", NULL),
REGULATOR_SUPPLY("vdd_1v8_cam3", NULL),
- REGULATOR_SUPPLY("vdd_i2c", "6-0072"),
- REGULATOR_SUPPLY("vdd_i2c", "7-0072"),
+ REGULATOR_SUPPLY("dvdd", "6-0072"),
+ REGULATOR_SUPPLY("dvdd", "7-0072"),
REGULATOR_SUPPLY("vdd_i2c", "2-0033"),
};
diff --git a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
index 5416942ace40..0c55aa49acc0 100644
--- a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
+++ b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
@@ -181,7 +181,8 @@ static struct regulator_consumer_supply ricoh583_ldo8_supply_0[] = {
RICOH_PDATA_INIT(dc0, 0, 700, 1500, 0, 1, 1, 0, -1, 0, 0, 0,
RICOH583_EXT_PWRREQ2_CONTROL, 0);
-RICOH_PDATA_INIT(dc1, skubit0_0, 700, 1500, 0, 1, 1, 0, -1, 0, 0, 0, 0, 0);
+RICOH_PDATA_INIT(dc1, skubit0_0, 700, 1500, 0, 1, 1, 0, -1, 0, 0, 0,
+ RICOH583_EXT_PWRREQ1_CONTROL, 0);
RICOH_PDATA_INIT(dc2, 0, 900, 2400, 0, 1, 1, 0, -1, 0, 0, 0, 0, 0);
RICOH_PDATA_INIT(dc3, 0, 900, 2400, 0, 1, 1, 0, -1, 0, 0, 0, 0, 0);
@@ -448,13 +449,13 @@ static struct regulator_consumer_supply fixed_reg_en_vdd_pnl1_supply[] = {
/* CAM1_LDO_EN from AP GPIO KB_ROW6 R06*/
static struct regulator_consumer_supply fixed_reg_cam1_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam1", NULL),
- REGULATOR_SUPPLY("vdd", "6-0072"),
+ REGULATOR_SUPPLY("avdd", "6-0072"),
};
/* CAM2_LDO_EN from AP GPIO KB_ROW7 R07*/
static struct regulator_consumer_supply fixed_reg_cam2_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam2", NULL),
- REGULATOR_SUPPLY("vdd", "7-0072"),
+ REGULATOR_SUPPLY("avdd", "7-0072"),
};
/* CAM3_LDO_EN from AP GPIO KB_ROW8 S00*/
@@ -492,8 +493,8 @@ static struct regulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = {
REGULATOR_SUPPLY("vdd_1v8_cam1", NULL),
REGULATOR_SUPPLY("vdd_1v8_cam2", NULL),
REGULATOR_SUPPLY("vdd_1v8_cam3", NULL),
- REGULATOR_SUPPLY("vdd_i2c", "6-0072"),
- REGULATOR_SUPPLY("vdd_i2c", "7-0072"),
+ REGULATOR_SUPPLY("dvdd", "6-0072"),
+ REGULATOR_SUPPLY("dvdd", "7-0072"),
REGULATOR_SUPPLY("vdd_i2c", "2-0033"),
};
@@ -558,13 +559,13 @@ static struct regulator_consumer_supply fixed_reg_en_vddio_vid_oc_supply[] = {
#define FIXED_REG(_id, _var, _name, _in_supply, _always_on, _boot_on, \
_gpio_nr, _active_high, _boot_state, _millivolts) \
FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, _boot_on, \
- _gpio_nr, _active_high, _boot_state, _millivolts, true)
+ _gpio_nr, _active_high, _boot_state, _millivolts, false)
/* common to most of boards*/
FIXED_REG(0, en_5v_cp, en_5v_cp, NULL, 1, 0, TPS6591X_GPIO_0, true, 1, 5000);
FIXED_REG(1, en_5v0, en_5v0, NULL, 0, 0, TPS6591X_GPIO_4, true, 0, 5000);
FIXED_REG(2, en_ddr, en_ddr, NULL, 0, 0, TPS6591X_GPIO_3, true, 1, 1500);
-FIXED_REG(3, en_3v3_sys, en_3v3_sys, NULL, 0, 0, TPS6591X_GPIO_1, true, 0, 3300);
+FIXED_REG(3, en_3v3_sys, en_3v3_sys, NULL, 0, 0, TPS6591X_GPIO_1, true, 1, 3300);
FIXED_REG(4, en_vdd_bl, en_vdd_bl, NULL, 0, 0, TEGRA_GPIO_PK3, true, 1, 5000);
FIXED_REG(5, en_3v3_modem, en_3v3_modem, NULL, 1, 0, TEGRA_GPIO_PD6, true, 1, 3300);
FIXED_REG(6, en_vdd_pnl1, en_vdd_pnl1, FIXED_SUPPLY(en_3v3_sys), 0, 0, TEGRA_GPIO_PL4, true, 1, 3300);
diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c
index fada59bb8707..79d8d6116edc 100644
--- a/arch/arm/mach-tegra/board-cardhu-power.c
+++ b/arch/arm/mach-tegra/board-cardhu-power.c
@@ -191,7 +191,7 @@ static struct regulator_consumer_supply tps6591x_ldo8_supply_0[] = {
TPS_PDATA_INIT(vdd1, skubit0_0, 600, 1500, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, 0);
TPS_PDATA_INIT(vdd1, skubit0_1, 600, 1500, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, 0);
-TPS_PDATA_INIT(vdd2, 0, 600, 1500, 0, 1, 1, 0, -1, 0, 0, 0, 0);
+TPS_PDATA_INIT(vdd2, 0, 600, 1500, 0, 0, 1, 0, -1, 0, 0, 0, 0);
TPS_PDATA_INIT(vddctrl, 0, 600, 1400, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_EN1, 0);
TPS_PDATA_INIT(vio, 0, 1500, 3300, 0, 1, 1, 0, -1, 0, 0, 0, 0);
@@ -486,7 +486,8 @@ int __init cardhu_regulator_init(void)
/* E1291-A04/A05: Enable DEV_SLP and enable sleep on GPIO2 */
if ((board_info.board_id == BOARD_E1291) &&
((board_info.fab == BOARD_FAB_A04) ||
- (board_info.fab == BOARD_FAB_A05))) {
+ (board_info.fab == BOARD_FAB_A05) ||
+ (board_info.fab == BOARD_FAB_A07))) {
tps_platform.dev_slp_en = true;
tps_platform.gpio_init_data = tps_gpio_pdata_e1291_a04;
tps_platform.num_gpioinit_data =
@@ -602,13 +603,13 @@ static struct regulator_consumer_supply fixed_reg_en_vdd_pnl1_supply[] = {
/* CAM1_LDO_EN from AP GPIO KB_ROW6 R06*/
static struct regulator_consumer_supply fixed_reg_cam1_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam1", NULL),
- REGULATOR_SUPPLY("vdd", "6-0072"),
+ REGULATOR_SUPPLY("avdd", "6-0072"),
};
/* CAM2_LDO_EN from AP GPIO KB_ROW7 R07*/
static struct regulator_consumer_supply fixed_reg_cam2_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam2", NULL),
- REGULATOR_SUPPLY("vdd", "7-0072"),
+ REGULATOR_SUPPLY("avdd", "7-0072"),
};
/* CAM3_LDO_EN from AP GPIO KB_ROW8 S00*/
@@ -646,8 +647,8 @@ static struct regulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = {
REGULATOR_SUPPLY("vdd_1v8_cam1", NULL),
REGULATOR_SUPPLY("vdd_1v8_cam2", NULL),
REGULATOR_SUPPLY("vdd_1v8_cam3", NULL),
- REGULATOR_SUPPLY("vdd_i2c", "6-0072"),
- REGULATOR_SUPPLY("vdd_i2c", "7-0072"),
+ REGULATOR_SUPPLY("dvdd", "6-0072"),
+ REGULATOR_SUPPLY("dvdd", "7-0072"),
REGULATOR_SUPPLY("vdd_i2c", "2-0033"),
};
@@ -1027,7 +1028,8 @@ int __init cardhu_fixed_regulator_init(void)
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e1291_a03);
fixed_reg_devs = fixed_reg_devs_e1291_a03;
} else if ((board_info.fab == BOARD_FAB_A04) ||
- (board_info.fab == BOARD_FAB_A05)) {
+ (board_info.fab == BOARD_FAB_A05) ||
+ (board_info.fab == BOARD_FAB_A07)) {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e1291_a04);
fixed_reg_devs = fixed_reg_devs_e1291_a04;
} else {
@@ -1151,17 +1153,6 @@ int __init cardhu_suspend_init(void)
return 0;
}
-static struct tegra_tsensor_pmu_data tpdata = {
- .poweroff_reg_addr = 0x3F,
- .poweroff_reg_data = 0x80,
- .reset_tegra = 1,
- .controller_type = 0,
- .i2c_controller_id = 4,
- .pinmux = 0,
- .pmu_16bit_ops = 0,
- .pmu_i2c_addr = 0x2D,
-};
-
#ifdef CONFIG_TEGRA_EDP_LIMITS
int __init cardhu_edp_init(void)
diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c
index fddf01f3e39d..c4e631ddc108 100644
--- a/arch/arm/mach-tegra/board-cardhu-sdhci.c
+++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/board-harmony-sdhci.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-2012 NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -63,7 +63,7 @@ static struct resource wifi_resource[] = {
},
};
-static struct platform_device cardhu_wifi_device = {
+static struct platform_device broadcom_wifi_device = {
.name = "bcm4329_wlan",
.id = 1,
.num_resources = 1,
@@ -73,6 +73,15 @@ static struct platform_device cardhu_wifi_device = {
},
};
+static struct platform_device marvell_wifi_device = {
+ .name = "mrvl8797_wlan",
+ .id = 1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &cardhu_wifi_control,
+ },
+};
+
static struct resource sdhci_resource0[] = {
[0] = {
.start = INT_SDMMC1,
@@ -112,6 +121,7 @@ static struct resource sdhci_resource3[] = {
},
};
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
static struct embedded_sdio_data embedded_sdio_data2 = {
.cccr = {
.sdio_vsn = 2,
@@ -126,18 +136,25 @@ static struct embedded_sdio_data embedded_sdio_data2 = {
.device = 0x4329,
},
};
+#endif
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.mmc_data = {
.register_status_notify = cardhu_wifi_status_register,
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
.embedded_sdio = &embedded_sdio_data2,
- .built_in = 1,
+#endif
+ .built_in = 0,
},
+#ifndef CONFIG_MMC_EMBEDDED_SDIO
+ .pm_flags = MMC_PM_KEEP_POWER,
+#endif
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -150,8 +167,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.cd_gpio = CARDHU_SD_CD,
.wp_gpio = CARDHU_SD_WP,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = true,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = true,
.vdd_rail_name = "vddio_sdmmc1",
.slot_rail_name = "vddio_sd_slot",
.vdd_max_uv = 3320000,
@@ -166,11 +184,11 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
.power_gpio = -1,
.is_8bit = 1,
.tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
.mmc_data = {
.built_in = 1,
}
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -250,6 +268,7 @@ static int cardhu_wifi_reset(int on)
static int __init cardhu_wifi_init(void)
{
int rc;
+ int commchip_id = tegra_get_commchip_id();
rc = gpio_request(CARDHU_WLAN_PWR, "wlan_power");
if (rc)
@@ -275,10 +294,28 @@ static int __init cardhu_wifi_init(void)
if (rc)
pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
- platform_device_register(&cardhu_wifi_device);
+ if (commchip_id == COMMCHIP_MARVELL_SD8797)
+ platform_device_register(&marvell_wifi_device);
+ else
+ platform_device_register(&broadcom_wifi_device);
+
return 0;
}
+#ifdef CONFIG_TEGRA_PREPOWER_WIFI
+static int __init cardhu_wifi_prepower(void)
+{
+ if (!machine_is_cardhu())
+ return 0;
+
+ cardhu_wifi_power(1);
+
+ return 0;
+}
+
+subsys_initcall_sync(cardhu_wifi_prepower);
+#endif
+
int __init cardhu_sdhci_init(void)
{
struct board_info board_info;
diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c
index 0f7d2f95d54d..66b3c9dc8ef3 100644
--- a/arch/arm/mach-tegra/board-cardhu-sensors.c
+++ b/arch/arm/mach-tegra/board-cardhu-sensors.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu-sensors.c
*
- * Copyright (c) 2010-2011, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -40,6 +40,7 @@
#include <mach/fb.h>
#include <mach/gpio.h>
#include <media/ov5650.h>
+#include <media/ov5640.h>
#include <media/ov14810.h>
#include <media/ov2710.h>
#include <media/tps61050.h>
@@ -464,6 +465,86 @@ struct ov2710_platform_data cardhu_ov2710_data = {
.power_off = cardhu_ov2710_power_off,
};
+static int cardhu_ov5640_power_on(void)
+{
+ /* CSI-B and front sensor are muxed on cardhu */
+ gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 1);
+
+ /* Boards E1198 and E1291 are of Cardhu personality
+ * and donot have TCA6416 exp for camera */
+ if ((board_info.board_id == BOARD_E1198) ||
+ (board_info.board_id == BOARD_E1291)) {
+
+ gpio_direction_output(CAM1_POWER_DWN_GPIO, 0);
+ gpio_direction_output(CAM2_POWER_DWN_GPIO, 0);
+ gpio_direction_output(CAM3_POWER_DWN_GPIO, 0);
+ mdelay(10);
+
+ if (cardhu_vdd_cam3 == NULL) {
+ cardhu_vdd_cam3 = regulator_get(NULL, "vdd_cam3");
+ if (WARN_ON(IS_ERR(cardhu_vdd_cam3))) {
+ pr_err("%s: couldn't get regulator vdd_cam3: %ld\n",
+ __func__, PTR_ERR(cardhu_vdd_cam3));
+ goto reg_alloc_fail;
+ }
+ }
+ regulator_enable(cardhu_vdd_cam3);
+ }
+
+ /* Enable VDD_1V8_Cam3 */
+ if (cardhu_1v8_cam3 == NULL) {
+ cardhu_1v8_cam3 = regulator_get(NULL, "vdd_1v8_cam3");
+ if (WARN_ON(IS_ERR(cardhu_1v8_cam3))) {
+ pr_err("%s: couldn't get regulator vdd_1v8_cam3: %ld\n",
+ __func__, PTR_ERR(cardhu_1v8_cam3));
+ goto reg_alloc_fail;
+ }
+ }
+ regulator_enable(cardhu_1v8_cam3);
+ mdelay(5);
+
+ return 0;
+
+reg_alloc_fail:
+ if (cardhu_1v8_cam3) {
+ regulator_put(cardhu_1v8_cam3);
+ cardhu_1v8_cam3 = NULL;
+ }
+ if (cardhu_vdd_cam3) {
+ regulator_put(cardhu_vdd_cam3);
+ cardhu_vdd_cam3 = NULL;
+ }
+
+ return -ENODEV;
+}
+
+static int cardhu_ov5640_power_off(void)
+{
+ /* CSI-B and front sensor are muxed on cardhu */
+ gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 1);
+
+ /* Boards E1198 and E1291 are of Cardhu personality
+ * and donot have TCA6416 exp for camera */
+ if ((board_info.board_id == BOARD_E1198) ||
+ (board_info.board_id == BOARD_E1291)) {
+ gpio_direction_output(CAM1_POWER_DWN_GPIO, 1);
+ gpio_direction_output(CAM2_POWER_DWN_GPIO, 1);
+ gpio_direction_output(CAM3_POWER_DWN_GPIO, 1);
+ }
+
+ if (cardhu_1v8_cam3)
+ regulator_disable(cardhu_1v8_cam3);
+ if (cardhu_vdd_cam3)
+ regulator_disable(cardhu_vdd_cam3);
+
+ return 0;
+}
+
+struct ov5640_platform_data cardhu_ov5640_data = {
+ .power_on = cardhu_ov5640_power_on,
+ .power_off = cardhu_ov5640_power_off,
+};
+
static const struct i2c_board_info cardhu_i2c3_board_info[] = {
{
I2C_BOARD_INFO("pca9546", 0x70),
@@ -471,34 +552,56 @@ static const struct i2c_board_info cardhu_i2c3_board_info[] = {
},
};
+
+static struct nvc_gpio_pdata sh532u_gpio_pdata[] = {
+ { SH532U_GPIO_RESET, TEGRA_GPIO_PBB0, false, 0, },
+};
+
static struct sh532u_platform_data sh532u_left_pdata = {
+ .cfg = NVC_CFG_NODEV,
.num = 1,
.sync = 2,
.dev_name = "focuser",
- .gpio_reset = TEGRA_GPIO_PBB0,
+ .gpio_count = ARRAY_SIZE(sh532u_gpio_pdata),
+ .gpio = sh532u_gpio_pdata,
};
static struct sh532u_platform_data sh532u_right_pdata = {
+ .cfg = NVC_CFG_NODEV,
.num = 2,
.sync = 1,
.dev_name = "focuser",
- .gpio_reset = TEGRA_GPIO_PBB0,
+ .gpio_count = ARRAY_SIZE(sh532u_gpio_pdata),
+ .gpio = sh532u_gpio_pdata,
+};
+
+static struct nvc_gpio_pdata pm269_sh532u_left_gpio_pdata[] = {
+ { SH532U_GPIO_RESET, CAM1_RST_L_GPIO, false, 0, },
};
static struct sh532u_platform_data pm269_sh532u_left_pdata = {
+ .cfg = 0,
.num = 1,
.sync = 2,
.dev_name = "focuser",
- .gpio_reset = CAM1_RST_L_GPIO,
+ .gpio_count = ARRAY_SIZE(pm269_sh532u_left_gpio_pdata),
+ .gpio = pm269_sh532u_left_gpio_pdata,
+};
+
+static struct nvc_gpio_pdata pm269_sh532u_right_gpio_pdata[] = {
+ { SH532U_GPIO_RESET, CAM2_RST_L_GPIO, false, 0, },
};
static struct sh532u_platform_data pm269_sh532u_right_pdata = {
+ .cfg = 0,
.num = 2,
.sync = 1,
.dev_name = "focuser",
- .gpio_reset = CAM2_RST_L_GPIO,
+ .gpio_count = ARRAY_SIZE(pm269_sh532u_right_gpio_pdata),
+ .gpio = pm269_sh532u_right_gpio_pdata,
};
+
static struct nvc_torch_pin_state cardhu_tps61050_pinstate = {
.mask = 0x0008, /*VGP3*/
.values = 0x0008,
@@ -565,6 +668,10 @@ static struct i2c_board_info cardhu_i2c8_board_info[] = {
I2C_BOARD_INFO("ov2710", 0x36),
.platform_data = &cardhu_ov2710_data,
},
+ {
+ I2C_BOARD_INFO("ov5640", 0x3C),
+ .platform_data = &cardhu_ov5640_data,
+ },
};
static int nct_get_temp(void *_data, long *temp)
diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c
index 339011ea254d..9083828b8352 100644
--- a/arch/arm/mach-tegra/board-cardhu.c
+++ b/arch/arm/mach-tegra/board-cardhu.c
@@ -62,6 +62,7 @@
#include "board.h"
#include "clock.h"
#include "board-cardhu.h"
+#include "board-touch.h"
#include "devices.h"
#include "gpio-names.h"
#include "fuse.h"
@@ -71,19 +72,17 @@
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
- .temp_throttle = 85000,
.temp_shutdown = 90000,
.temp_offset = TDIODE_OFFSET, /* temps based on tdiode */
#ifdef CONFIG_TEGRA_EDP_LIMITS
.edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
.hysteresis_edp = 3000,
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
.tc1 = 0,
.tc2 = 1,
.passive_delay = 2000,
-#else
- .hysteresis_throttle = 1000,
#endif
};
@@ -227,7 +226,7 @@ static struct tegra_i2c_platform_data cardhu_i2c1_platform_data = {
static struct tegra_i2c_platform_data cardhu_i2c2_platform_data = {
.adapter_nr = 1,
.bus_count = 1,
- .bus_clk_rate = { 100000, 0 },
+ .bus_clk_rate = { 400000, 0 },
.is_clkon_always = true,
.scl_gpio = {TEGRA_GPIO_PT5, 0},
.sda_gpio = {TEGRA_GPIO_PT6, 0},
@@ -574,6 +573,10 @@ static struct platform_device *cardhu_spi_devices[] __initdata = {
&tegra_spi_device4,
};
+static struct platform_device *touch_spi_device[] __initdata = {
+ &tegra_spi_device1,
+};
+
struct spi_clk_parent spi_parent_clk[] = {
[0] = {.name = "pll_p"},
#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
@@ -595,9 +598,10 @@ static void __init cardhu_spi_init(void)
{
int i;
struct clk *c;
- struct board_info board_info;
+ struct board_info board_info, display_board_info;
tegra_get_board_info(&board_info);
+ tegra_get_display_board_info(&display_board_info);
for (i = 0; i < ARRAY_SIZE(spi_parent_clk); ++i) {
c = tegra_get_clock_by_name(spi_parent_clk[i].name);
@@ -615,6 +619,10 @@ static void __init cardhu_spi_init(void)
platform_add_devices(cardhu_spi_devices,
ARRAY_SIZE(cardhu_spi_devices));
+ if (display_board_info.board_id == BOARD_DISPLAY_PM313) {
+ platform_add_devices(touch_spi_device,
+ ARRAY_SIZE(touch_spi_device));
+ }
if (board_info.board_id == BOARD_E1198) {
tegra_spi_device2.dev.platform_data = &cardhu_spi_pdata;
platform_device_register(&tegra_spi_device2);
@@ -821,30 +829,43 @@ static struct i2c_board_info __initdata atmel_i2c_info[] = {
}
};
+static __initdata struct tegra_clk_init_table spi_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "sbc1", "pll_p", 52000000, true},
+ { NULL, NULL, 0, 0},
+};
+
static int __init cardhu_touch_init(void)
{
struct board_info BoardInfo;
- tegra_gpio_enable(TEGRA_GPIO_PH4);
- tegra_gpio_enable(TEGRA_GPIO_PH6);
-
- gpio_request(TEGRA_GPIO_PH4, "atmel-irq");
- gpio_direction_input(TEGRA_GPIO_PH4);
+ tegra_get_display_board_info(&BoardInfo);
+ if (BoardInfo.board_id == BOARD_DISPLAY_PM313) {
+ tegra_clk_init_from_table(spi_clk_init_table);
- gpio_request(TEGRA_GPIO_PH6, "atmel-reset");
- gpio_direction_output(TEGRA_GPIO_PH6, 0);
- msleep(1);
- gpio_set_value(TEGRA_GPIO_PH6, 1);
- msleep(100);
+ touch_init_raydium(TEGRA_GPIO_PH4, TEGRA_GPIO_PH6, 2);
+ } else {
+ tegra_gpio_enable(TEGRA_GPIO_PH4);
+ tegra_gpio_enable(TEGRA_GPIO_PH6);
+
+ gpio_request(TEGRA_GPIO_PH4, "atmel-irq");
+ gpio_direction_input(TEGRA_GPIO_PH4);
+
+ gpio_request(TEGRA_GPIO_PH6, "atmel-reset");
+ gpio_direction_output(TEGRA_GPIO_PH6, 0);
+ msleep(1);
+ gpio_set_value(TEGRA_GPIO_PH6, 1);
+ msleep(100);
+
+ tegra_get_board_info(&BoardInfo);
+ if ((BoardInfo.sku & SKU_TOUCH_MASK) == SKU_TOUCH_2000) {
+ atmel_mxt_info.config = config_sku2000;
+ atmel_mxt_info.config_crc = MXT_CONFIG_CRC_SKU2000;
+ }
- tegra_get_board_info(&BoardInfo);
- if ((BoardInfo.sku & SKU_TOUCH_MASK) == SKU_TOUCH_2000) {
- atmel_mxt_info.config = config_sku2000;
- atmel_mxt_info.config_crc = MXT_CONFIG_CRC_SKU2000;
+ i2c_register_board_info(1, atmel_i2c_info, 1);
}
- i2c_register_board_info(1, atmel_i2c_info, 1);
-
return 0;
}
diff --git a/arch/arm/mach-tegra/board-cardhu.h b/arch/arm/mach-tegra/board-cardhu.h
index ba2a0d05b46c..27d9e4739911 100644
--- a/arch/arm/mach-tegra/board-cardhu.h
+++ b/arch/arm/mach-tegra/board-cardhu.h
@@ -76,6 +76,8 @@
#define BOARD_FAB_A03 0x3
#define BOARD_FAB_A04 0x4
#define BOARD_FAB_A05 0x5
+#define BOARD_FAB_A06 0x6
+#define BOARD_FAB_A07 0x7
/* Display Board ID */
#define BOARD_DISPLAY_PM313 0x030D
diff --git a/arch/arm/mach-tegra/board-enterprise-memory.c b/arch/arm/mach-tegra/board-enterprise-memory.c
index fca1a08ed701..36a8264c2a21 100644
--- a/arch/arm/mach-tegra/board-enterprise-memory.c
+++ b/arch/arm/mach-tegra/board-enterprise-memory.c
@@ -24,7 +24,7 @@
#include "board.h"
-static const struct tegra_emc_table enterprise_emc_tables_h5tc2g[] = {
+static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
{
0x32, /* Rev 3.2 */
12750, /* SDRAM frequency */
@@ -717,7 +717,7 @@ static const struct tegra_emc_table enterprise_emc_tables_h5tc2g[] = {
0x00000000, /* EMC_CTT_DURATION */
0x80000ce6, /* EMC_DYN_SELF_REF_CONTROL */
0x00000006, /* MC_EMEM_ARB_CFG */
- 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0xc0000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
0x00000003, /* MC_EMEM_ARB_TIMING_RP */
0x0000000c, /* MC_EMEM_ARB_TIMING_RC */
@@ -747,6 +747,729 @@ static const struct tegra_emc_table enterprise_emc_tables_h5tc2g[] = {
},
};
+static const struct tegra_emc_table enterprise_emc_tables_kmkts0_a03[] = {
+ {
+ 0x32, /* Rev 3.2 */
+ 12750, /* SDRAM frequency */
+ {
+ 0x00000000, /* EMC_RC */
+ 0x00000001, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x0000002f, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000000b, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000002, /* EMC_TXSR */
+ 0x00000002, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x00000036, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000164, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00050001, /* MC_EMEM_ARB_CFG */
+ 0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x77230303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 25500, /* SDRAM frequency */
+ {
+ 0x00000001, /* EMC_RC */
+ 0x00000003, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x00000060, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000018, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000004, /* EMC_TXSR */
+ 0x00000004, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x0000006b, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x0000000a, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800001c5, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x73e30303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 51000, /* SDRAM frequency */
+ {
+ 0x00000003, /* EMC_RC */
+ 0x00000006, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x000000c0, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000030, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000008, /* EMC_TXSR */
+ 0x00000008, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x000000d5, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x00000013, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72c30303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 102000, /* SDRAM frequency */
+ {
+ 0x00000006, /* EMC_RC */
+ 0x0000000d, /* EMC_RFC */
+ 0x00000004, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x00000181, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000060, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x0000000f, /* EMC_TXSR */
+ 0x0000000f, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x000001a9, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x0000000a, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060403, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72430504, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x0000000a, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 204000, /* SDRAM frequency */
+ {
+ 0x0000000c, /* EMC_RC */
+ 0x0000001a, /* EMC_RFC */
+ 0x00000008, /* EMC_RAS */
+ 0x00000003, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x00000006, /* EMC_W2P */
+ 0x00000003, /* EMC_RD_RCD */
+ 0x00000003, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000002, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x0000000b, /* EMC_RDV */
+ 0x00000303, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000000c0, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000003, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x0000001d, /* EMC_TXSR */
+ 0x0000001d, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000b, /* EMC_TFAW */
+ 0x00000005, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x00000351, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x004400a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS0 */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS1 */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS2 */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000e0220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000013, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02030001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00070506, /* MC_EMEM_ARB_DA_COVERS */
+ 0x71e40a07, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000013, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010042, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 533000, /* SDRAM frequency */
+ {
+ 0x0000001f, /* EMC_RC */
+ 0x00000045, /* EMC_RFC */
+ 0x00000016, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000008, /* EMC_R2W */
+ 0x00000009, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x0000000d, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000005, /* EMC_RRD */
+ 0x00000003, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000009, /* EMC_QUSE */
+ 0x00000006, /* EMC_QRST */
+ 0x0000000d, /* EMC_QSAFE */
+ 0x00000010, /* EMC_RDV */
+ 0x000007e1, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000001f8, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000003, /* EMC_PDEX2RD */
+ 0x00000009, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x0000004b, /* EMC_TXSR */
+ 0x0000004b, /* EMC_TXSRDLL */
+ 0x00000008, /* EMC_TCKE */
+ 0x0000001b, /* EMC_TFAW */
+ 0x0000000c, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x000008ab, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006282, /* EMC_FBIO_CFG5 */
+ 0xf0120091, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00000008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000a0220, /* EMC_XM2CMDPADCTRL */
+ 0x0800003d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f408, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x000000c0, /* EMC_ZCAL_WAIT_CNT */
+ 0x000e000e, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10202, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800010dc, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000008, /* MC_EMEM_ARB_CFG */
+ 0x80000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000010, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000d, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x05040002, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00110c10, /* MC_EMEM_ARB_DA_COVERS */
+ 0x70281811, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000030, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x000100c2, /* Mode Register 1 */
+ 0x00020006, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+};
+
int enterprise_emc_init(void)
{
struct board_info board_info;
@@ -754,8 +1477,12 @@ int enterprise_emc_init(void)
tegra_get_board_info(&board_info);
if (board_info.fab <= BOARD_FAB_A02)
- tegra_init_emc(enterprise_emc_tables_h5tc2g,
- ARRAY_SIZE(enterprise_emc_tables_h5tc2g));
+ tegra_init_emc(enterprise_emc_tables_kmmll0_a02,
+ ARRAY_SIZE(enterprise_emc_tables_kmmll0_a02));
+ else
+ tegra_init_emc(enterprise_emc_tables_kmkts0_a03,
+ ARRAY_SIZE(enterprise_emc_tables_kmkts0_a03));
+
return 0;
}
diff --git a/arch/arm/mach-tegra/board-enterprise-panel.c b/arch/arm/mach-tegra/board-enterprise-panel.c
index 913a5775eaf3..5b3dacea135f 100644
--- a/arch/arm/mach-tegra/board-enterprise-panel.c
+++ b/arch/arm/mach-tegra/board-enterprise-panel.c
@@ -28,7 +28,7 @@
#include <linux/tegra_pwm_bl.h>
#include <asm/atomic.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -63,6 +63,7 @@
#ifdef CONFIG_TEGRA_DC
static struct regulator *enterprise_dsi_reg;
+static bool dsi_regulator_status;
static struct regulator *enterprise_lcd_reg;
static struct regulator *enterprise_hdmi_reg;
@@ -149,7 +150,6 @@ static bool kernel_1st_panel_init = true;
static int enterprise_backlight_notify(struct device *unused, int brightness)
{
int cur_sd_brightness = atomic_read(&sd_brightness);
- int orig_brightness = brightness;
/* SD brightness is a percentage, 8-bit value. */
brightness = (brightness * cur_sd_brightness) / 255;
@@ -454,27 +454,61 @@ static struct tegra_dc_platform_data enterprise_disp2_pdata = {
.emc_clk_rate = 300000000,
};
-static int enterprise_dsi_panel_enable(void)
+static int avdd_dsi_csi_rail_enable(void)
{
int ret;
- struct board_info board_info;
- tegra_get_board_info(&board_info);
+ if (dsi_regulator_status == true)
+ return 0;
if (enterprise_dsi_reg == NULL) {
enterprise_dsi_reg = regulator_get(NULL, "avdd_dsi_csi");
if (IS_ERR_OR_NULL(enterprise_dsi_reg)) {
pr_err("dsi: Could not get regulator avdd_dsi_csi\n");
- enterprise_dsi_reg = NULL;
- return PTR_ERR(enterprise_dsi_reg);
+ enterprise_dsi_reg = NULL;
+ return PTR_ERR(enterprise_dsi_reg);
}
}
ret = regulator_enable(enterprise_dsi_reg);
if (ret < 0) {
- printk(KERN_ERR
- "DSI regulator avdd_dsi_csi could not be enabled\n");
+ pr_err("DSI regulator avdd_dsi_csi could not be enabled\n");
return ret;
}
+ dsi_regulator_status = true;
+ return 0;
+}
+
+static int avdd_dsi_csi_rail_disable(void)
+{
+ int ret;
+
+ if (dsi_regulator_status == false)
+ return 0;
+
+ if (enterprise_dsi_reg == NULL) {
+ pr_warn("%s: unbalanced disable\n", __func__);
+ return -EIO;
+ }
+
+ ret = regulator_disable(enterprise_dsi_reg);
+ if (ret < 0) {
+ pr_err("DSI regulator avdd_dsi_csi cannot be disabled\n");
+ return ret;
+ }
+ dsi_regulator_status = false;
+ return 0;
+}
+
+static int enterprise_dsi_panel_enable(void)
+{
+ int ret;
+ struct board_info board_info;
+
+ tegra_get_board_info(&board_info);
+
+ ret = avdd_dsi_csi_rail_enable();
+ if (ret)
+ return ret;
#if DSI_PANEL_RESET
@@ -562,8 +596,8 @@ static void enterprise_stereo_set_orientation(int mode)
#ifdef CONFIG_TEGRA_DC
static int enterprise_dsi_panel_postsuspend(void)
{
- /* Do nothing for enterprise dsi panel */
- return 0;
+ /* Disable enterprise dsi rail */
+ return avdd_dsi_csi_rail_disable();
}
#endif
@@ -782,17 +816,12 @@ static void enterprise_panel_early_suspend(struct early_suspend *h)
fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
if (num_registered_fb > 1)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
-#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
+ cpufreq_store_default_gov();
+ if (cpufreq_change_gov(cpufreq_conservative_gov))
+ pr_err("Early_suspend: Error changing governor to %s\n",
+ cpufreq_conservative_gov);
#endif
}
@@ -801,7 +830,8 @@ static void enterprise_panel_late_resume(struct early_suspend *h)
unsigned i;
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ if (cpufreq_restore_default_gov())
+ pr_err("Early_suspend: Unable to restore governor\n");
#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
diff --git a/arch/arm/mach-tegra/board-enterprise-pinmux.c b/arch/arm/mach-tegra/board-enterprise-pinmux.c
index 8d18e3296af3..fc5851848864 100644
--- a/arch/arm/mach-tegra/board-enterprise-pinmux.c
+++ b/arch/arm/mach-tegra/board-enterprise-pinmux.c
@@ -215,7 +215,7 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D6, RSVD1, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D7, RSVD1, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, TRISTATE, INPUT),
DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, INPUT),
diff --git a/arch/arm/mach-tegra/board-enterprise-power.c b/arch/arm/mach-tegra/board-enterprise-power.c
index 9d7a4d6e6dff..c7598ab56139 100644
--- a/arch/arm/mach-tegra/board-enterprise-power.c
+++ b/arch/arm/mach-tegra/board-enterprise-power.c
@@ -147,6 +147,7 @@ static struct regulator_consumer_supply tps80031_vana_supply_common[] = {
static struct regulator_consumer_supply tps80031_ldo1_supply_a02[] = {
REGULATOR_SUPPLY("avdd_dsi_csi", NULL),
+ REGULATOR_SUPPLY("avdd_hsic", NULL),
REGULATOR_SUPPLY("pwrdet_mipi", NULL),
};
@@ -373,8 +374,8 @@ static struct tps80031_bg_platform_data battery_gauge_data = {
static struct tps80031_subdev_info tps80031_devs_a02[] = {
- TPS80031_DEVS_COMMON,
TPS_REG(VIO, vio, a02),
+ TPS80031_DEVS_COMMON,
TPS_REG(SMPS4, smps4, a02),
TPS_REG(LDO1, ldo1, a02),
TPS_REG(LDO4, ldo4, a02),
@@ -386,8 +387,8 @@ static struct tps80031_subdev_info tps80031_devs_a02[] = {
};
static struct tps80031_subdev_info tps80031_devs_a03[] = {
- TPS80031_DEVS_COMMON,
TPS_REG(VIO, vio, a03),
+ TPS80031_DEVS_COMMON,
TPS_REG(SMPS4, smps4, a03),
TPS_REG(LDO1, ldo1, a03),
TPS_REG(LDO4, ldo4, a03),
@@ -462,7 +463,7 @@ static struct regulator_consumer_supply fixed_reg_vdd_fuse_en_supply[] = {
static struct regulator_consumer_supply gpio_reg_sdmmc3_vdd_sel_supply[] = {
REGULATOR_SUPPLY("vddio_sdmmc3_2v85_1v8", NULL),
REGULATOR_SUPPLY("sdmmc3_compu_pu", NULL),
- REGULATOR_SUPPLY("vddio_sdmmc3", NULL),
+ REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.2"),
REGULATOR_SUPPLY("vsys_3v7", NULL),
};
@@ -643,8 +644,12 @@ FIXED_REG(8, lcd_1v8_en, NULL,
ADD_FIXED_REG(cam_ldo_1v8_en)
static struct platform_device *fixed_regs_devices_a02[] = {
- FIXED_REGS_COMMON,
- ADD_FIXED_REG(pmu_3v3_en),
+ ADD_FIXED_REG(pmu_5v15_en), \
+ ADD_FIXED_REG(pmu_3v3_en), \
+ ADD_FIXED_REG(pmu_hdmi_5v0_en), \
+ ADD_FIXED_REG(vdd_fuse_en), \
+ ADD_FIXED_REG(cam_ldo_2v8_en), \
+ ADD_FIXED_REG(cam_ldo_1v8_en)
};
static struct platform_device *fixed_regs_devices_a03[] = {
diff --git a/arch/arm/mach-tegra/board-enterprise-sdhci.c b/arch/arm/mach-tegra/board-enterprise-sdhci.c
index af1a9ea3dd59..4e9690899082 100644
--- a/arch/arm/mach-tegra/board-enterprise-sdhci.c
+++ b/arch/arm/mach-tegra/board-enterprise-sdhci.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise-sdhci.c
*
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-2012 NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -109,6 +109,7 @@ static struct resource sdhci_resource3[] = {
},
};
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
static struct embedded_sdio_data embedded_sdio_data0 = {
.cccr = {
.sdio_vsn = 2,
@@ -123,26 +124,36 @@ static struct embedded_sdio_data embedded_sdio_data0 = {
.device = 0x4329,
},
};
+#endif
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.mmc_data = {
.register_status_notify = enterprise_wifi_status_register,
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
.embedded_sdio = &embedded_sdio_data0,
+#endif
/* FIXME need to revert the built_in change
once we use get the signal strength fix of
bcmdhd driver from broadcom for bcm4329 chipset*/
.built_in = 0,
},
+#ifndef CONFIG_MMC_EMBEDDED_SDIO
+ .pm_flags = MMC_PM_KEEP_POWER,
+#endif
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
+ .tap_delay = 0x0F,
.max_clk_limit = 45000000,
+ .ddr_clk_limit = 41000000,
};
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
};
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
@@ -150,6 +161,8 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
.wp_gpio = -1,
.power_gpio = -1,
.is_8bit = 1,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
.mmc_data = {
.built_in = 1,
}
@@ -223,6 +236,20 @@ static int enterprise_wifi_reset(int on)
return 0;
}
+#ifdef CONFIG_TEGRA_PREPOWER_WIFI
+static int __init enterprise_wifi_prepower(void)
+{
+ if (!machine_is_tegra_enterprise())
+ return 0;
+
+ enterprise_wifi_power(1);
+
+ return 0;
+}
+
+subsys_initcall_sync(enterprise_wifi_prepower);
+#endif
+
static int __init enterprise_wifi_init(void)
{
int rc;
diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c
index 71b26469e487..a95ee617b1a8 100644
--- a/arch/arm/mach-tegra/board-enterprise.c
+++ b/arch/arm/mach-tegra/board-enterprise.c
@@ -65,19 +65,17 @@
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
- .temp_throttle = 85000,
.temp_shutdown = 90000,
.temp_offset = TDIODE_OFFSET, /* temps based on tdiode */
#ifdef CONFIG_TEGRA_EDP_LIMITS
.edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
.hysteresis_edp = 3000,
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
.tc1 = 0,
.tc2 = 1,
.passive_delay = 2000,
-#else
- .hysteresis_throttle = 1000,
#endif
};
@@ -207,7 +205,7 @@ static struct tegra_i2c_platform_data enterprise_i2c1_platform_data = {
static struct tegra_i2c_platform_data enterprise_i2c2_platform_data = {
.adapter_nr = 1,
.bus_count = 1,
- .bus_clk_rate = { 100000, 0 },
+ .bus_clk_rate = { 400000, 0 },
.is_clkon_always = true,
.scl_gpio = {TEGRA_GPIO_PT5, 0},
.sda_gpio = {TEGRA_GPIO_PT6, 0},
@@ -951,8 +949,17 @@ static void enterprise_baseband_init(void)
static void enterprise_nfc_init(void)
{
+ struct board_info bi;
+
tegra_gpio_enable(TEGRA_GPIO_PS4);
tegra_gpio_enable(TEGRA_GPIO_PM6);
+
+ /* Enable firmware GPIO PX7 for board E1205 */
+ tegra_get_board_info(&bi);
+ if (bi.board_id == BOARD_E1205 && bi.fab >= BOARD_FAB_A03) {
+ nfc_pdata.firm_gpio = TEGRA_GPIO_PX7;
+ tegra_gpio_enable(TEGRA_GPIO_PX7);
+ }
}
static void __init tegra_enterprise_init(void)
diff --git a/arch/arm/mach-tegra/board-harmony-panel.c b/arch/arm/mach-tegra/board-harmony-panel.c
index c24039652bc5..9c3d296dd8d3 100644
--- a/arch/arm/mach-tegra/board-harmony-panel.c
+++ b/arch/arm/mach-tegra/board-harmony-panel.c
@@ -26,7 +26,7 @@
#include <mach/dc.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/tegra_fb.h>
#include <mach/fb.h>
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index 86e9615f785a..9bf8cde056a3 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -425,7 +425,8 @@ static struct tegra_sdhci_platform_data sdhci_pdata4 = {
.is_8bit = 1,
};
-static int __init harmony_wifi_init(void)
+#ifdef CONFIG_TEGRA_PREPOWER_WIFI
+static int __init harmony_wifi_prepower(void)
{
int gpio_pwr, gpio_rst;
@@ -458,7 +459,8 @@ static int __init harmony_wifi_init(void)
* supply of external PMU and 1.2V regulator) are properly enabled,
* and mmc driver has not yet probed for a device on SDIO bus.
*/
-subsys_initcall_sync(harmony_wifi_init);
+subsys_initcall_sync(harmony_wifi_prepower);
+#endif
static void __init tegra_harmony_init(void)
{
diff --git a/arch/arm/mach-tegra/board-kai-memory.c b/arch/arm/mach-tegra/board-kai-memory.c
index 5a22cebcfff5..1f812ece741b 100644
--- a/arch/arm/mach-tegra/board-kai-memory.c
+++ b/arch/arm/mach-tegra/board-kai-memory.c
@@ -28,126 +28,6 @@
static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
{
0x32, /* Rev 3.2 */
- 12750, /* SDRAM frequency */
- {
- 0x00000000, /* EMC_RC */
- 0x00000003, /* EMC_RFC */
- 0x00000000, /* EMC_RAS */
- 0x00000000, /* EMC_RP */
- 0x00000002, /* EMC_R2W */
- 0x0000000a, /* EMC_W2R */
- 0x00000005, /* EMC_R2P */
- 0x0000000b, /* EMC_W2P */
- 0x00000000, /* EMC_RD_RCD */
- 0x00000000, /* EMC_WR_RCD */
- 0x00000003, /* EMC_RRD */
- 0x00000001, /* EMC_REXT */
- 0x00000000, /* EMC_WEXT */
- 0x00000005, /* EMC_WDV */
- 0x00000005, /* EMC_QUSE */
- 0x00000004, /* EMC_QRST */
- 0x00000009, /* EMC_QSAFE */
- 0x0000000b, /* EMC_RDV */
- 0x00000060, /* EMC_REFRESH */
- 0x00000000, /* EMC_BURST_REFRESH_NUM */
- 0x00000018, /* EMC_PRE_REFRESH_REQ_CNT */
- 0x00000002, /* EMC_PDEX2WR */
- 0x00000002, /* EMC_PDEX2RD */
- 0x00000001, /* EMC_PCHG2PDEN */
- 0x00000000, /* EMC_ACT2PDEN */
- 0x00000007, /* EMC_AR2PDEN */
- 0x0000000f, /* EMC_RW2PDEN */
- 0x00000005, /* EMC_TXSR */
- 0x00000005, /* EMC_TXSRDLL */
- 0x00000004, /* EMC_TCKE */
- 0x00000001, /* EMC_TFAW */
- 0x00000000, /* EMC_TRPAB */
- 0x00000004, /* EMC_TCLKSTABLE */
- 0x00000005, /* EMC_TCLKSTOP */
- 0x00000064, /* EMC_TREFBW */
- 0x00000006, /* EMC_QUSE_EXTRA */
- 0x00000004, /* EMC_FBIO_CFG6 */
- 0x00000000, /* EMC_ODT_WRITE */
- 0x00000000, /* EMC_ODT_READ */
- 0x00004288, /* EMC_FBIO_CFG5 */
- 0x007800a4, /* EMC_CFG_DIG_DLL */
- 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
- 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
- 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
- 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
- 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
- 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
- 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
- 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
- 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
- 0x000002a0, /* EMC_XM2CMDPADCTRL */
- 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
- 0x00000000, /* EMC_XM2DQPADCTRL2 */
- 0x77fff884, /* EMC_XM2CLKPADCTRL */
- 0x01f1f108, /* EMC_XM2COMPPADCTRL */
- 0x05057404, /* EMC_XM2VTTGENPADCTRL */
- 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
- 0x08000168, /* EMC_XM2QUSEPADCTRL */
- 0x08000000, /* EMC_XM2DQSPADCTRL3 */
- 0x00000802, /* EMC_CTT_TERM_CTRL */
- 0x00000000, /* EMC_ZCAL_INTERVAL */
- 0x00000040, /* EMC_ZCAL_WAIT_CNT */
- 0x000c000c, /* EMC_MRS_WAIT_CNT */
- 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
- 0x00000000, /* EMC_CTT */
- 0x00000000, /* EMC_CTT_DURATION */
- 0x800001c5, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00050001, /* MC_EMEM_ARB_CFG */
- 0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
- 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
- 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
- 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
- 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
- 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */
- 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
- 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
- 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
- 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
- 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
- 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
- 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
- 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
- 0x000a0502, /* MC_EMEM_ARB_DA_COVERS */
- 0x77e30303, /* MC_EMEM_ARB_MISC0 */
- 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
- 0xe8000000, /* EMC_FBIO_SPARE */
- 0xff00ff00, /* EMC_CFG_RSV */
- },
- 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
- 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
- 0x00000001, /* EMC_CFG.PERIODIC_QRST */
- 0x80001221, /* Mode Register 0 */
- 0x80100003, /* Mode Register 1 */
- 0x80200008, /* Mode Register 2 */
- 0x00000001, /* EMC_CFG.DYN_SELF_REF */
- },
- {
- 0x32, /* Rev 3.2 */
25500, /* SDRAM frequency */
{
0x00000001, /* EMC_RC */
@@ -526,7 +406,7 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000005, /* EMC_WDV */
0x00000005, /* EMC_QUSE */
0x00000004, /* EMC_QRST */
- 0x00000009, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_QSAFE */
0x0000000b, /* EMC_RDV */
0x00000607, /* EMC_REFRESH */
0x00000000, /* EMC_BURST_REFRESH_NUM */
@@ -666,20 +546,20 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000005, /* EMC_TCLKSTOP */
0x00000a2a, /* EMC_TREFBW */
0x00000000, /* EMC_QUSE_EXTRA */
- 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000004, /* EMC_FBIO_CFG6 */
0x00000000, /* EMC_ODT_WRITE */
0x00000000, /* EMC_ODT_READ */
0x00007088, /* EMC_FBIO_CFG5 */
0x002600a4, /* EMC_CFG_DIG_DLL */
0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
- 0x00014000, /* EMC_DLL_XFORM_DQS0 */
- 0x00014000, /* EMC_DLL_XFORM_DQS1 */
- 0x00014000, /* EMC_DLL_XFORM_DQS2 */
- 0x00014000, /* EMC_DLL_XFORM_DQS3 */
- 0x00014000, /* EMC_DLL_XFORM_DQS4 */
- 0x00014000, /* EMC_DLL_XFORM_DQS5 */
- 0x00014000, /* EMC_DLL_XFORM_DQS6 */
- 0x00014000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS7 */
0x00000000, /* EMC_DLL_XFORM_QUSE0 */
0x00000000, /* EMC_DLL_XFORM_QUSE1 */
0x00000000, /* EMC_DLL_XFORM_QUSE2 */
@@ -696,10 +576,10 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
- 0x00020000, /* EMC_DLL_XFORM_DQ0 */
- 0x00020000, /* EMC_DLL_XFORM_DQ1 */
- 0x00020000, /* EMC_DLL_XFORM_DQ2 */
- 0x00020000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00034000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00034000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00034000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00034000, /* EMC_DLL_XFORM_DQ3 */
0x000002a0, /* EMC_XM2CMDPADCTRL */
0x0800013d, /* EMC_XM2DQSPADCTRL2 */
0x00000000, /* EMC_XM2DQPADCTRL2 */
diff --git a/arch/arm/mach-tegra/board-kai-panel.c b/arch/arm/mach-tegra/board-kai-panel.c
index 53661ced7c8e..4073afe2fc8d 100644
--- a/arch/arm/mach-tegra/board-kai-panel.c
+++ b/arch/arm/mach-tegra/board-kai-panel.c
@@ -27,7 +27,7 @@
#include <linux/pwm_backlight.h>
#include <asm/atomic.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -620,27 +620,20 @@ static void kai_panel_early_suspend(struct early_suspend *h)
fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
if (num_registered_fb > 1)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
-
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+ cpufreq_store_default_gov();
+ if (cpufreq_change_gov(cpufreq_conservative_gov))
+ pr_err("Early_suspend: Error changing governor to %s\n",
+ cpufreq_conservative_gov);
#endif
-
}
static void kai_panel_late_resume(struct early_suspend *h)
{
unsigned i;
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ if (cpufreq_restore_default_gov())
+ pr_err("Early_suspend: Unable to restore governor\n");
#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
diff --git a/arch/arm/mach-tegra/board-kai-pinmux.c b/arch/arm/mach-tegra/board-kai-pinmux.c
index 1bc64bdb1558..fa750f15ca7e 100644
--- a/arch/arm/mach-tegra/board-kai-pinmux.c
+++ b/arch/arm/mach-tegra/board-kai-pinmux.c
@@ -379,7 +379,7 @@ static __initdata struct tegra_pingroup_config kai_pinmux_common[] = {
DEFAULT_PINMUX(SPI2_MISO, SPI2, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(SPI2_MOSI, SPI2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(KB_ROW11, KBC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW11, KBC, PULL_UP, TRISTATE, INPUT),
DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(KB_ROW13, KBC, NORMAL, TRISTATE, OUTPUT),
};
@@ -469,6 +469,7 @@ static void __init kai_pinmux_audio_init(void)
static struct gpio_init_pin_info init_gpio_mode_kai_common[] = {
GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD7, false, 0),
GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC6, false, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC7, false, 1),
};
static void __init kai_gpio_init_configure(void)
diff --git a/arch/arm/mach-tegra/board-kai-power.c b/arch/arm/mach-tegra/board-kai-power.c
index edb0ee35abb3..e89b2bd2246d 100644
--- a/arch/arm/mach-tegra/board-kai-power.c
+++ b/arch/arm/mach-tegra/board-kai-power.c
@@ -181,7 +181,7 @@ MAX77663_PDATA_INIT(sd0, 600000, 3387500, NULL, 1, 0, 0,
0, 0, -1, FPS_SRC_NONE, -1, -1, EN2_CTRL_SD0 | SD_FSRADE_DISABLE);
MAX77663_PDATA_INIT(sd1, 800000, 1587500, NULL, 1, 0, 0,
- 1, 1, -1, FPS_SRC_1, -1, -1, SD_FSRADE_DISABLE);
+ 1, 1, -1, FPS_SRC_1, FPS_POWER_PERIOD_0, -1, SD_FSRADE_DISABLE);
MAX77663_PDATA_INIT(sd2, 1800000, 1800000, NULL, 1, 0, 0,
1, 1, -1, FPS_SRC_NONE, -1, -1, 0);
@@ -459,7 +459,7 @@ FIXED_REG(3, en_1v8_cam_a00, en_1v8_cam, max77663_rails(sd2),
FIXED_REG(4, en_vddio_vid_a00, en_vddio_vid, NULL,
0, 0, TEGRA_GPIO_PB2, true, 0, 5000);
FIXED_REG(5, en_3v3_modem_a00, en_3v3_modem, NULL,
- 1, 1, TEGRA_GPIO_PP0, true, 0, 3300);
+ 0, 1, TEGRA_GPIO_PP0, true, 0, 3300);
FIXED_REG(6, en_vdd_pnl_a00, en_vdd_pnl, FIXED_SUPPLY(en_3v3_sys_a00),
0, 0, TEGRA_GPIO_PW1, true, 0, 3300);
FIXED_REG(7, en_cam3_ldo_a00, en_cam3_ldo, FIXED_SUPPLY(en_3v3_sys_a00),
@@ -483,9 +483,9 @@ FIXED_REG(3, en_1v8_cam_a01, en_1v8_cam, max77663_rails(sd2),
FIXED_REG(4, en_vddio_vid_a01, en_vddio_vid, NULL,
0, 0, TEGRA_GPIO_PB2, true, 0, 5000);
FIXED_REG(5, en_3v3_modem_a01, en_3v3_modem, NULL,
- 1, 1, TEGRA_GPIO_PP0, true, 0, 3300);
+ 0, 1, TEGRA_GPIO_PP0, true, 0, 3300);
FIXED_REG(6, en_vdd_pnl_a01, en_vdd_pnl, FIXED_SUPPLY(en_3v3_sys_a01),
- 0, 0, TEGRA_GPIO_PW1, true, 0, 3300);
+ 0, 1, TEGRA_GPIO_PW1, true, 0, 3300);
FIXED_REG(7, en_cam3_ldo_a01, en_cam3_ldo, FIXED_SUPPLY(en_3v3_sys_a01),
0, 0, TEGRA_GPIO_PR7, true, 0, 3300);
FIXED_REG(8, en_vdd_com_a01, en_vdd_com, FIXED_SUPPLY(en_3v3_sys_a01),
diff --git a/arch/arm/mach-tegra/board-kai-sdhci.c b/arch/arm/mach-tegra/board-kai-sdhci.c
index 3e4899271085..8d1d4a9bd4a8 100644
--- a/arch/arm/mach-tegra/board-kai-sdhci.c
+++ b/arch/arm/mach-tegra/board-kai-sdhci.c
@@ -101,32 +101,21 @@ static struct resource sdhci_resource3[] = {
},
};
-static struct embedded_sdio_data embedded_sdio_data2 = {
- .cccr = {
- .sdio_vsn = 2,
- .multi_block = 1,
- .low_speed = 0,
- .wide_bus = 0,
- .high_power = 1,
- .high_speed = 1,
- },
- .cis = {
- .vendor = 0x0097,
- .device = 0x4076,
- },
-};
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.mmc_data = {
.register_status_notify = kai_wifi_status_register,
- /* .embedded_sdio = &embedded_sdio_data2, */
- .built_in = 1,
+ .built_in = 0,
},
+#ifndef CONFIG_MMC_EMBEDDED_SDIO
+ .pm_flags = MMC_PM_KEEP_POWER,
+#endif
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -140,8 +129,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.cd_gpio = KAI_SD_CD,
.wp_gpio = -1,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = true,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = true,
.vdd_rail_name = "vddio_sdmmc1",
.slot_rail_name = "vddio_sd_slot",
.vdd_max_uv = 3320000,
@@ -156,11 +146,11 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
.power_gpio = -1,
.is_8bit = 1,
.tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
.mmc_data = {
.built_in = 1,
}
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -227,6 +217,20 @@ static int kai_wifi_power(int power_on)
return 0;
}
+#ifdef CONFIG_TEGRA_PREPOWER_WIFI
+static int __init kai_wifi_prepower(void)
+{
+ if (!machine_is_kai())
+ return 0;
+
+ kai_wifi_power(1);
+
+ return 0;
+}
+
+subsys_initcall_sync(kai_wifi_prepower);
+#endif
+
static int __init kai_wifi_init(void)
{
int rc;
diff --git a/arch/arm/mach-tegra/board-kai-sensors.c b/arch/arm/mach-tegra/board-kai-sensors.c
index 82784ebd9735..9564aaf0cfde 100644
--- a/arch/arm/mach-tegra/board-kai-sensors.c
+++ b/arch/arm/mach-tegra/board-kai-sensors.c
@@ -21,11 +21,14 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/nct1008.h>
#include <linux/cm3217.h>
#include <linux/mpu.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <asm/mach-types.h>
#include <mach/gpio.h>
+#include <mach/thermal.h>
#include <media/ov2710.h>
#include "board.h"
#include "board-kai.h"
@@ -34,6 +37,110 @@
static struct regulator *kai_1v8_cam3;
static struct regulator *kai_vdd_cam3;
+#ifndef CONFIG_TEGRA_INTERNAL_TSENSOR_EDP_SUPPORT
+static int nct_get_temp(void *_data, long *temp)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_get_temp(data, temp);
+}
+
+static int nct_get_temp_low(void *_data, long *temp)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_get_temp_low(data, temp);
+}
+
+static int nct_set_limits(void *_data,
+ long lo_limit_milli,
+ long hi_limit_milli)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_set_limits(data,
+ lo_limit_milli,
+ hi_limit_milli);
+}
+
+static int nct_set_alert(void *_data,
+ void (*alert_func)(void *),
+ void *alert_data)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_set_alert(data, alert_func, alert_data);
+}
+
+static int nct_set_shutdown_temp(void *_data, long shutdown_temp)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_set_shutdown_temp(data, shutdown_temp);
+}
+
+static void nct1008_probe_callback(struct nct1008_data *data)
+{
+ struct tegra_thermal_device *thermal_device;
+
+ thermal_device = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!thermal_device) {
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ thermal_device->name = "nct72";
+ thermal_device->data = data;
+ thermal_device->offset = TDIODE_OFFSET;
+ thermal_device->get_temp = nct_get_temp;
+ thermal_device->get_temp_low = nct_get_temp_low;
+ thermal_device->set_limits = nct_set_limits;
+ thermal_device->set_alert = nct_set_alert;
+ thermal_device->set_shutdown_temp = nct_set_shutdown_temp;
+
+ tegra_thermal_set_device(thermal_device);
+}
+#endif
+
+static struct nct1008_platform_data kai_nct1008_pdata = {
+ .supported_hwrev = true,
+ .ext_range = true,
+ .conv_rate = 0x09, /* 0x09 corresponds to 32Hz conversion rate */
+ .offset = 8, /* 4 * 2C. 1C for device accuracies */
+#ifndef CONFIG_TEGRA_INTERNAL_TSENSOR_EDP_SUPPORT
+ .probe_callback = nct1008_probe_callback,
+#endif
+};
+
+static struct i2c_board_info kai_i2c4_nct1008_board_info[] = {
+ {
+ I2C_BOARD_INFO("nct72", 0x4C),
+ .platform_data = &kai_nct1008_pdata,
+ .irq = -1,
+ }
+};
+
+static int kai_nct1008_init(void)
+{
+ int ret = 0;
+
+ /* FIXME: enable irq when throttling is supported */
+ kai_i2c4_nct1008_board_info[0].irq =
+ TEGRA_GPIO_TO_IRQ(KAI_TEMP_ALERT_GPIO);
+
+ ret = gpio_request(KAI_TEMP_ALERT_GPIO, "temp_alert");
+ if (ret < 0) {
+ pr_err("%s: gpio_request failed\n", __func__);
+ return ret;
+ }
+
+ ret = gpio_direction_input(KAI_TEMP_ALERT_GPIO);
+ if (ret < 0) {
+ pr_err("%s: set gpio to input failed\n", __func__);
+ gpio_free(KAI_TEMP_ALERT_GPIO);
+ }
+ else
+ tegra_gpio_enable(KAI_TEMP_ALERT_GPIO);
+
+ return ret;
+}
+
static struct cm3217_platform_data kai_cm3217_pdata = {
.levels = {10, 160, 225, 320, 640, 1280, 2600, 5800, 8000, 10240},
.golden_adc = 0,
@@ -83,7 +190,7 @@ static int kai_ov2710_power_on(void)
kai_vdd_cam3 = regulator_get(NULL, "vdd_cam3");
if (WARN_ON(IS_ERR(kai_vdd_cam3))) {
pr_err("%s: couldn't get regulator vdd_cam3: %d\n",
- __func__, PTR_ERR(kai_vdd_cam3));
+ __func__, (int)PTR_ERR(kai_vdd_cam3));
goto reg_get_vdd_cam3_fail;
}
}
@@ -93,7 +200,7 @@ static int kai_ov2710_power_on(void)
kai_1v8_cam3 = regulator_get(NULL, "vdd_1v8_cam3");
if (WARN_ON(IS_ERR(kai_1v8_cam3))) {
pr_err("%s: couldn't get regulator vdd_1v8_cam3: %d\n",
- __func__, PTR_ERR(kai_1v8_cam3));
+ __func__, (int)PTR_ERR(kai_1v8_cam3));
goto reg_get_vdd_1v8_cam3_fail;
}
}
@@ -245,6 +352,15 @@ static void mpuirq_init(void)
int __init kai_sensors_init(void)
{
+ int err;
+
+ err = kai_nct1008_init();
+ if (err)
+ pr_err("%s: nct1008 init failed\n", __func__);
+ else
+ i2c_register_board_info(4, kai_i2c4_nct1008_board_info,
+ ARRAY_SIZE(kai_i2c4_nct1008_board_info));
+
kai_camera_init();
i2c_register_board_info(2, kai_i2c2_board_info,
diff --git a/arch/arm/mach-tegra/board-kai.c b/arch/arm/mach-tegra/board-kai.c
index fc35f4a86382..c455fba4cef9 100644
--- a/arch/arm/mach-tegra/board-kai.c
+++ b/arch/arm/mach-tegra/board-kai.c
@@ -68,19 +68,17 @@
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
- .temp_throttle = 85000,
.temp_shutdown = 90000,
.temp_offset = TDIODE_OFFSET, /* temps based on tdiode */
#ifdef CONFIG_TEGRA_EDP_LIMITS
.edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
.hysteresis_edp = 3000,
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
.tc1 = 0,
.tc2 = 1,
.passive_delay = 2000,
-#else
- .hysteresis_throttle = 1000,
#endif
};
@@ -722,8 +720,6 @@ static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
[0] = {
.instance = 0,
.vbus_gpio = -1,
- .vbus_irq = MAX77663_IRQ_BASE +
- MAX77663_IRQ_ACOK_RISING,
},
[1] = {
.instance = 1,
@@ -815,7 +811,6 @@ static void __init tegra_kai_init(void)
kai_edp_init();
#endif
kai_uart_init();
- kai_tsensor_init();
kai_audio_init();
platform_add_devices(kai_devices, ARRAY_SIZE(kai_devices));
tegra_ram_console_debug_init();
diff --git a/arch/arm/mach-tegra/board-kai.h b/arch/arm/mach-tegra/board-kai.h
index 1f7c16ebf590..d0a1b277073c 100644
--- a/arch/arm/mach-tegra/board-kai.h
+++ b/arch/arm/mach-tegra/board-kai.h
@@ -95,6 +95,8 @@ int __init touch_init_synaptics_kai(void);
#define KAI_TS_ID1_PG TEGRA_PINGROUP_GMI_WAIT
#define KAI_TS_ID2_PG TEGRA_PINGROUP_GMI_WP_N
+#define KAI_TEMP_ALERT_GPIO TEGRA_GPIO_PS3
+
#define MPU_TYPE_MPU3050 1
#define MPU_TYPE_MPU6050 2
#define MPU_GYRO_TYPE MPU_TYPE_MPU6050
diff --git a/arch/arm/mach-tegra/board-p1852-panel.c b/arch/arm/mach-tegra/board-p1852-panel.c
index 8940af0c0b62..ee4c4671a48f 100644
--- a/arch/arm/mach-tegra/board-p1852-panel.c
+++ b/arch/arm/mach-tegra/board-p1852-panel.c
@@ -20,7 +20,7 @@
#include <asm/mach-types.h>
#include <linux/platform_device.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
diff --git a/arch/arm/mach-tegra/board-p1852-pinmux.c b/arch/arm/mach-tegra/board-p1852-pinmux.c
index a59f6590e332..1503c80c8269 100644
--- a/arch/arm/mach-tegra/board-p1852-pinmux.c
+++ b/arch/arm/mach-tegra/board-p1852-pinmux.c
@@ -329,9 +329,9 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
VI_PINMUX(VI_D2, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D3, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
- VI_PINMUX(VI_D4, VI, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D4, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D5, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
- VI_PINMUX(VI_D6, VI, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D6, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D7, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D8, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D9, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
diff --git a/arch/arm/mach-tegra/board-p1852.c b/arch/arm/mach-tegra/board-p1852.c
index 020671a7513b..43bef9975187 100644
--- a/arch/arm/mach-tegra/board-p1852.c
+++ b/arch/arm/mach-tegra/board-p1852.c
@@ -103,7 +103,7 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
{ "pll_a", NULL, 552960000, false},
{ "pll_a_out0", NULL, 12288000, false},
{ "d_audio", "pll_a_out0", 12288000, false},
- { "nor", "pll_p", 86500000, true},
+ { "nor", "pll_p", 102000000, true},
{ "uarta", "pll_p", 480000000, true},
{ "uartd", "pll_p", 480000000, true},
{ "uarte", "pll_p", 480000000, true},
@@ -141,6 +141,7 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
{ "i2c4", "pll_p", 3200000, true},
{ "i2c5", "pll_p", 3200000, true},
{ "sdmmc2", "pll_p", 104000000, false},
+ {"wake.sclk", NULL, 334000000, true },
{ NULL, NULL, 0, 0},
};
@@ -332,6 +333,11 @@ static void p1852_spi_init(void)
p852_register_spidev();
}
+static struct platform_device tegra_camera = {
+ .name = "tegra_camera",
+ .id = -1,
+};
+
static struct platform_device *p1852_devices[] __initdata = {
#if defined(CONFIG_TEGRA_IOVMM_SMMU)
&tegra_smmu_device,
@@ -339,6 +345,7 @@ static struct platform_device *p1852_devices[] __initdata = {
#if defined(CONFIG_TEGRA_AVP)
&tegra_avp_device,
#endif
+ &tegra_camera,
&tegra_wdt_device
};
@@ -402,12 +409,12 @@ static struct tegra_nor_platform_data p1852_nor_data = {
.chip_parms = {
/* FIXME: Need to use characterized value */
.timing_default = {
- .timing0 = 0xA0400273,
- .timing1 = 0x00030402,
+ .timing0 = 0x30300263,
+ .timing1 = 0x00030302,
},
.timing_read = {
- .timing0 = 0xA0400273,
- .timing1 = 0x00030402,
+ .timing0 = 0x30300263,
+ .timing1 = 0x00030302,
},
},
};
diff --git a/arch/arm/mach-tegra/board-touch-raydium_spi.c b/arch/arm/mach-tegra/board-touch-raydium_spi.c
index 9f5843a0e62e..eb13fc4a44ab 100644
--- a/arch/arm/mach-tegra/board-touch-raydium_spi.c
+++ b/arch/arm/mach-tegra/board-touch-raydium_spi.c
@@ -220,15 +220,15 @@ int __init touch_init_raydium(int irq_gpio, int reset_gpio, int platform)
switch (platform) {
case 0:
pr_info("Raydium Kai PCB based touch init\n");
- rm31080ts_data.config = rm31080_config_kai_pcb;
+ rm31080ts_data.config = (char *) rm31080_config_kai_pcb;
break;
case 1:
pr_info("Raydium Kai On-Board touch init\n");
- rm31080ts_data.config = rm31080_config_kai_mainboard;
+ rm31080ts_data.config = (char *) rm31080_config_kai_mainboard;
break;
case 2:
pr_info("Raydium cardhu touch init\n");
- rm31080ts_data.config = rm31080_config_cardhu;
+ rm31080ts_data.config = (char *) rm31080_config_cardhu;
break;
default:
pr_err("touch_id error, no touch\n");
diff --git a/arch/arm/mach-tegra/board-touch.h b/arch/arm/mach-tegra/board-touch.h
new file mode 100644
index 000000000000..61b64d3f495a
--- /dev/null
+++ b/arch/arm/mach-tegra/board-touch.h
@@ -0,0 +1,25 @@
+/*
+ * arch/arm/mach-tegra/board-touch.h
+ *
+ * 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/>.
+ */
+
+#ifndef _MACH_TEGRA_BOARD_TOUCH_H
+#define _MACH_TEGRA_BOARD_TOUCH_H
+
+
+int __init touch_init_raydium(int irq_gpio, int reset_gpio, int platform);
+
+#endif
diff --git a/arch/arm/mach-tegra/board-ventana-panel.c b/arch/arm/mach-tegra/board-ventana-panel.c
index 4cacd3dc4216..f396557411b8 100644
--- a/arch/arm/mach-tegra/board-ventana-panel.c
+++ b/arch/arm/mach-tegra/board-ventana-panel.c
@@ -27,7 +27,7 @@
#include <linux/earlysuspend.h>
#include <linux/pwm_backlight.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -240,8 +240,8 @@ static struct tegra_fb_data ventana_fb_data = {
static struct tegra_fb_data ventana_hdmi_fb_data = {
.win = 0,
- .xres = 1366,
- .yres = 768,
+ .xres = 640,
+ .yres = 480,
.bits_per_pixel = 32,
.flags = TEGRA_FB_FLIP_ON_PROBE,
};
@@ -366,16 +366,10 @@ static void ventana_panel_early_suspend(struct early_suspend *h)
if (num_registered_fb > 1)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+ cpufreq_store_default_gov();
+ if (cpufreq_change_gov(cpufreq_conservative_gov))
+ pr_err("Early_suspend: Error changing governor to %s\n",
+ cpufreq_conservative_gov);
#endif
}
@@ -383,7 +377,8 @@ static void ventana_panel_late_resume(struct early_suspend *h)
{
unsigned i;
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ if (cpufreq_restore_default_gov())
+ pr_err("Early_suspend: Unable to restore governor\n");
#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
@@ -444,6 +439,11 @@ int __init ventana_panel_init(void)
tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start,
min(tegra_fb_size, tegra_bootloader_fb_size));
+ /* Copy the bootloader fb to the fb2. */
+ tegra_move_framebuffer(tegra_fb2_start, tegra_bootloader_fb_start,
+ min(tegra_fb2_size, tegra_bootloader_fb_size));
+
+
#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
if (!err)
err = nvhost_device_register(&ventana_disp1_device);
diff --git a/arch/arm/mach-tegra/board-ventana-pinmux.c b/arch/arm/mach-tegra/board-ventana-pinmux.c
index 9f3447264599..eb371384ed4c 100644
--- a/arch/arm/mach-tegra/board-ventana-pinmux.c
+++ b/arch/arm/mach-tegra/board-ventana-pinmux.c
@@ -47,11 +47,11 @@
}
static __initdata struct tegra_drive_pingroup_config ventana_drive_pinmux[] = {
- DEFAULT_DRIVE(DDC),
DEFAULT_DRIVE(VI1),
DEFAULT_DRIVE(SDIO1),
SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
SET_DRIVE(VI2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
SET_DRIVE(AT1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
@@ -126,7 +126,7 @@ static __initdata struct tegra_pingroup_config ventana_pinmux[] = {
{TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
diff --git a/arch/arm/mach-tegra/board-ventana-power.c b/arch/arm/mach-tegra/board-ventana-power.c
index e36a4e7c2794..2acfdfed28e4 100644
--- a/arch/arm/mach-tegra/board-ventana-power.c
+++ b/arch/arm/mach-tegra/board-ventana-power.c
@@ -92,8 +92,8 @@ static struct regulator_consumer_supply tps658621_ldo6_supply[] = {
REGULATOR_SUPPLY("vcsi", "tegra_camera"),
REGULATOR_SUPPLY("vdd_dmic", "tegra-snd-wm8903.0"),
REGULATOR_SUPPLY("vdd_i2c", "3-0030"),
- REGULATOR_SUPPLY("vdd_i2c", "6-0072"),
- REGULATOR_SUPPLY("vdd_i2c", "7-0072"),
+ REGULATOR_SUPPLY("dvdd", "6-0072"),
+ REGULATOR_SUPPLY("dvdd", "7-0072"),
};
static struct regulator_consumer_supply tps658621_ldo7_supply[] = {
REGULATOR_SUPPLY("vdd_ldo7", NULL),
diff --git a/arch/arm/mach-tegra/board-ventana-sdhci.c b/arch/arm/mach-tegra/board-ventana-sdhci.c
index 49720cd7a6d7..188335ac98c5 100644
--- a/arch/arm/mach-tegra/board-ventana-sdhci.c
+++ b/arch/arm/mach-tegra/board-ventana-sdhci.c
@@ -108,6 +108,7 @@ static struct resource sdhci_resource3[] = {
},
};
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
static struct embedded_sdio_data embedded_sdio_data0 = {
.cccr = {
.sdio_vsn = 2,
@@ -122,13 +123,19 @@ static struct embedded_sdio_data embedded_sdio_data0 = {
.device = 0x4329,
},
};
+#endif
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.mmc_data = {
.register_status_notify = ventana_wifi_status_register,
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
.embedded_sdio = &embedded_sdio_data0,
- .built_in = 1,
+#endif
+ .built_in = 0,
},
+#ifndef CONFIG_MMC_EMBEDDED_SDIO
+ .pm_flags = MMC_PM_KEEP_POWER,
+#endif
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
@@ -224,6 +231,20 @@ static int ventana_wifi_reset(int on)
return 0;
}
+#ifdef CONFIG_TEGRA_PREPOWER_WIFI
+static int __init ventana_wifi_prepower(void)
+{
+ if (!machine_is_ventana())
+ return 0;
+
+ ventana_wifi_power(1);
+
+ return 0;
+}
+
+subsys_initcall_sync(ventana_wifi_prepower);
+#endif
+
static int __init ventana_wifi_init(void)
{
wifi_32k_clk = clk_get_sys(NULL, "blink");
diff --git a/arch/arm/mach-tegra/board-ventana-sensors.c b/arch/arm/mach-tegra/board-ventana-sensors.c
index 81184d54599d..574bdb25fc2a 100644
--- a/arch/arm/mach-tegra/board-ventana-sensors.c
+++ b/arch/arm/mach-tegra/board-ventana-sensors.c
@@ -143,20 +143,32 @@ struct ov2710_platform_data ventana_ov2710_data = {
};
+static struct nvc_gpio_pdata sh532u_left_gpio_pdata[] = {
+ { SH532U_GPIO_RESET, CAM2_RST_L_GPIO, false, 0, },
+ { SH532U_GPIO_GP1, CAM2_LDO_SHUTDN_L_GPIO, false, true, },
+};
+
static struct sh532u_platform_data sh532u_left_pdata = {
+ .cfg = NVC_CFG_NODEV,
.num = 1,
.sync = 2,
.dev_name = "focuser",
- .gpio_reset = CAM2_RST_L_GPIO,
- .gpio_en = CAM2_LDO_SHUTDN_L_GPIO,
+ .gpio_count = ARRAY_SIZE(sh532u_left_gpio_pdata),
+ .gpio = sh532u_left_gpio_pdata,
+};
+
+static struct nvc_gpio_pdata sh532u_right_gpio_pdata[] = {
+ { SH532U_GPIO_RESET, CAM1_RST_L_GPIO, false, 0, },
+ { SH532U_GPIO_GP1, CAM1_LDO_SHUTDN_L_GPIO, false, true, },
};
static struct sh532u_platform_data sh532u_right_pdata = {
+ .cfg = NVC_CFG_NODEV,
.num = 2,
.sync = 1,
.dev_name = "focuser",
- .gpio_reset = CAM1_RST_L_GPIO,
- .gpio_en = CAM1_LDO_SHUTDN_L_GPIO,
+ .gpio_count = ARRAY_SIZE(sh532u_right_gpio_pdata),
+ .gpio = sh532u_right_gpio_pdata,
};
diff --git a/arch/arm/mach-tegra/board-whistler-panel.c b/arch/arm/mach-tegra/board-whistler-panel.c
index 74075d4659c5..d171cf008a77 100644
--- a/arch/arm/mach-tegra/board-whistler-panel.c
+++ b/arch/arm/mach-tegra/board-whistler-panel.c
@@ -29,7 +29,7 @@
#include <linux/pwm_backlight.h>
#include <linux/tegra_pwm_bl.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -318,25 +318,22 @@ static void whistler_panel_early_suspend(struct early_suspend *h)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+ cpufreq_store_default_gov();
+ if (cpufreq_change_gov(cpufreq_conservative_gov))
+ pr_err("Early_suspend: Error changing governor to %s\n",
+ cpufreq_conservative_gov);
#endif
}
static void whistler_panel_late_resume(struct early_suspend *h)
{
unsigned i;
+
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ if (cpufreq_restore_default_gov())
+ pr_err("Early_suspend: Unable to restore governor\n");
#endif
+
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
}
diff --git a/arch/arm/mach-tegra/board-whistler-pinmux.c b/arch/arm/mach-tegra/board-whistler-pinmux.c
index 22c2f984c662..15ae9c76b19d 100644
--- a/arch/arm/mach-tegra/board-whistler-pinmux.c
+++ b/arch/arm/mach-tegra/board-whistler-pinmux.c
@@ -64,13 +64,15 @@
}
static __initdata struct tegra_drive_pingroup_config whistler_drive_pinmux[] = {
- DEFAULT_DRIVE(DBG),
- DEFAULT_DRIVE(DDC),
DEFAULT_DRIVE(VI1),
- DEFAULT_DRIVE(VI2),
DEFAULT_DRIVE(SDIO1),
SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 46, 46, SLOWEST, SLOWEST),
SET_DRIVE(DAP3, DISABLE, ENABLE, DIV_1, 46, 46, SLOWEST, SLOWEST),
+ SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C1 */
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C2-1 */
+ SET_DRIVE(AT1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C2-2 */
+ SET_DRIVE(VI2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C3 */
+ SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* DVC */
};
static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
@@ -93,7 +95,7 @@ static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
{TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GMA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
@@ -103,7 +105,7 @@ static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
{TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
@@ -155,7 +157,7 @@ static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
{TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
{TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDB, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDC, TEGRA_MUX_SDIO3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDD, TEGRA_MUX_SDIO3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
diff --git a/arch/arm/mach-tegra/board-whistler-sdhci.c b/arch/arm/mach-tegra/board-whistler-sdhci.c
index 08ebe33ae8b0..d98b1d53a52e 100644
--- a/arch/arm/mach-tegra/board-whistler-sdhci.c
+++ b/arch/arm/mach-tegra/board-whistler-sdhci.c
@@ -144,6 +144,7 @@ static struct resource sdhci_resource3[] = {
},
};
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
static struct embedded_sdio_data embedded_sdio_data1 = {
.cccr = {
.sdio_vsn = 2,
@@ -158,13 +159,19 @@ static struct embedded_sdio_data embedded_sdio_data1 = {
.device = 0x4329,
},
};
+#endif
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data1 = {
.mmc_data = {
.register_status_notify = whistler_wifi_status_register,
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
.embedded_sdio = &embedded_sdio_data1,
- .built_in = 1,
+#endif
+ .built_in = 0,
},
+#ifndef CONFIG_MMC_EMBEDDED_SDIO
+ .pm_flags = MMC_PM_KEEP_POWER,
+#endif
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
@@ -216,6 +223,20 @@ static struct platform_device tegra_sdhci_device3 = {
},
};
+#ifdef CONFIG_TEGRA_PREPOWER_WIFI
+static int __init whistler_wifi_prepower(void)
+{
+ if (!machine_is_whistler())
+ return 0;
+
+ whistler_wifi_power(1);
+
+ return 0;
+}
+
+subsys_initcall_sync(whistler_wifi_prepower);
+#endif
+
static int __init whistler_wifi_init(void)
{
gpio_request(WHISTLER_WLAN_PWR, "wlan_power");
diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c
index f1246454ed1b..ede0d0b11104 100644
--- a/arch/arm/mach-tegra/board-whistler.c
+++ b/arch/arm/mach-tegra/board-whistler.c
@@ -266,6 +266,7 @@ static struct tegra_i2c_platform_data whistler_i2c1_platform_data = {
.scl_gpio = {TEGRA_GPIO_PC4, 0},
.sda_gpio = {TEGRA_GPIO_PC5, 0},
.arb_recovery = arb_lost_recovery,
+ .slave_addr = 0xFC,
};
static const struct tegra_pingroup_config i2c2_ddc = {
@@ -287,6 +288,7 @@ static struct tegra_i2c_platform_data whistler_i2c2_platform_data = {
.scl_gpio = {0, TEGRA_GPIO_PT5},
.sda_gpio = {0, TEGRA_GPIO_PT6},
.arb_recovery = arb_lost_recovery,
+ .slave_addr = 0xFC,
};
static struct tegra_i2c_platform_data whistler_i2c3_platform_data = {
@@ -296,6 +298,7 @@ static struct tegra_i2c_platform_data whistler_i2c3_platform_data = {
.scl_gpio = {TEGRA_GPIO_PBB2, 0},
.sda_gpio = {TEGRA_GPIO_PBB3, 0},
.arb_recovery = arb_lost_recovery,
+ .slave_addr = 0xFC,
};
static struct tegra_i2c_platform_data whistler_dvc_platform_data = {
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 6d5a93cee6be..63095ce9336a 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -24,6 +24,7 @@
#include <linux/types.h>
#include <linux/power_supply.h>
+#include <linux/memory.h>
#define ADD_FIXED_VOLTAGE_REG(_name) (&_name##_fixed_voltage_device)
@@ -67,6 +68,14 @@
}
#endif
+/* This information is passed by bootloader */
+#define COMMCHIP_UNKNOWN 0
+#define COMMCHIP_NOCHIP 1
+#define COMMCHIP_BROADCOM_BCM4329 2
+#define COMMCHIP BROADCOM_BCM4330 3
+#define COMMCHIP_MARVELL_SD8797 4
+
+
struct memory_accessor;
void tegra_assert_system_reset(char mode, const char *cmd);
@@ -148,19 +157,21 @@ void tegra_get_board_info(struct board_info *);
void tegra_get_pmu_board_info(struct board_info *bi);
void tegra_get_display_board_info(struct board_info *bi);
void tegra_get_camera_board_info(struct board_info *bi);
+
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
-#define SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD 95
-#define SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD 50
-#define SET_CONSERVATIVE_GOVERNOR_FREQ_STEP 3
-
-void cpufreq_save_default_governor(void);
-void cpufreq_restore_default_governor(void);
-void cpufreq_set_conservative_governor(void);
-void cpufreq_set_conservative_governor_param(char *name, int value);
+#define MAX_GOV_NAME_LEN 16
+extern char cpufreq_default_gov[][MAX_GOV_NAME_LEN];
+extern char *cpufreq_conservative_gov;
+
+void cpufreq_store_default_gov(void);
+int cpufreq_restore_default_gov(void);
+int cpufreq_change_gov(char *target_gov);
#endif
+
int get_core_edp(void);
enum panel_type get_panel_type(void);
int tegra_get_modem_id(void);
+int tegra_get_commchip_id(void);
enum power_supply_type get_power_supply_type(void);
enum audio_codec_type get_audio_codec_type(void);
int get_maximum_cpu_current_supported(void);
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index f31da0bf1494..66a954fb6696 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -238,16 +238,9 @@ void clk_init(struct clk *c)
static int clk_enable_locked(struct clk *c)
{
int ret = 0;
- int rate = clk_get_rate_locked(c);
- bool set_rate = false;
-
- if (rate > c->max_rate) {
- rate = c->max_rate;
- set_rate = true;
- }
if (clk_is_auto_dvfs(c)) {
- ret = tegra_dvfs_set_rate(c, rate);
+ ret = tegra_dvfs_set_rate(c, clk_get_rate_locked(c));
if (ret)
return ret;
}
@@ -259,9 +252,6 @@ static int clk_enable_locked(struct clk *c)
return ret;
}
- if (set_rate)
- clk_set_rate_locked(c, rate);
-
if (c->ops && c->ops->enable) {
ret = c->ops->enable(c);
trace_clock_enable(c->name, 1, 0);
@@ -525,13 +515,11 @@ unsigned long clk_get_rate_all_locked(struct clk *c)
return rate;
}
-long clk_round_rate(struct clk *c, unsigned long rate)
+long clk_round_rate_locked(struct clk *c, unsigned long rate)
{
- unsigned long flags, max_rate;
+ unsigned long max_rate;
long ret;
- clk_lock_save(c, &flags);
-
if (!c->ops || !c->ops->round_rate) {
ret = -ENOSYS;
goto out;
@@ -544,6 +532,16 @@ long clk_round_rate(struct clk *c, unsigned long rate)
ret = c->ops->round_rate(c, rate);
out:
+ return ret;
+}
+
+long clk_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long flags;
+ long ret;
+
+ clk_lock_save(c, &flags);
+ ret = clk_round_rate_locked(c, rate);
clk_unlock_restore(c, &flags);
return ret;
}
@@ -1299,6 +1297,10 @@ static int clk_debugfs_register_one(struct clk *c)
if (!d)
goto err_out;
+ d = debugfs_create_u32("min", S_IRUGO, c->dent, (u32 *)&c->min_rate);
+ if (!d)
+ goto err_out;
+
d = debugfs_create_file(
"parent", parent_rate_mode, c->dent, c, &parent_fops);
if (!d)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index dde9e07292a7..a9945e3c2296 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -240,6 +240,7 @@ unsigned long clk_get_min_rate(struct clk *c);
unsigned long clk_get_rate_locked(struct clk *c);
int clk_set_rate_locked(struct clk *c, unsigned long rate);
int clk_set_parent_locked(struct clk *c, struct clk *parent);
+long clk_round_rate_locked(struct clk *c, unsigned long rate);
int tegra_clk_shared_bus_update(struct clk *c);
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
void tegra3_set_cpu_skipper_delay(int delay);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 4786aced9c57..78bd77dfb7d2 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -28,6 +28,7 @@
#include <linux/memblock.h>
#include <linux/bitops.h>
#include <linux/sched.h>
+#include <linux/cpufreq.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/system.h>
@@ -141,6 +142,7 @@ void tegra_assert_system_reset(char mode, const char *cmd)
#endif
}
static int modem_id;
+static int commchip_id;
static int sku_override;
static int debug_uart_port_id;
static enum audio_codec_type audio_codec_name;
@@ -153,6 +155,11 @@ static int max_cpu_current;
static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
/* name parent rate enabled */
{ "clk_m", NULL, 0, true },
+ { "emc", NULL, 0, true },
+ { "cpu", NULL, 0, true },
+ { "kfuse", NULL, 0, true },
+ { "fuse", NULL, 0, true },
+ { "sclk", NULL, 0, true },
#ifdef CONFIG_TEGRA_SILICON_PLATFORM
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
{ "pll_p", NULL, 216000000, true },
@@ -181,14 +188,7 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ "sclk", "pll_p_out4", 102000000, true },
{ "hclk", "sclk", 102000000, true },
{ "pclk", "hclk", 51000000, true },
- { "wake.sclk", NULL, 40000000, true },
- { "sbc5.sclk", NULL, 40000000, false},
- { "sbc6.sclk", NULL, 40000000, false},
#endif
- { "sbc1.sclk", NULL, 40000000, false},
- { "sbc2.sclk", NULL, 40000000, false},
- { "sbc3.sclk", NULL, 40000000, false},
- { "sbc4.sclk", NULL, 40000000, false},
#else
{ "pll_p", NULL, 216000000, true },
{ "pll_p_out1", "pll_p", 28800000, false },
@@ -199,25 +199,24 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ "sclk", "pll_p_out4", 108000000, true },
{ "hclk", "sclk", 108000000, true },
{ "pclk", "hclk", 54000000, true },
- { "pll_c", NULL, ULONG_MAX, false },
- { "pll_c_out1", "pll_c", 208000000, false },
#endif
#ifdef CONFIG_TEGRA_SLOW_CSITE
{ "csite", "clk_m", 1000000, true },
#else
{ "csite", NULL, 0, true },
#endif
- { "emc", NULL, 0, true },
- { "cpu", NULL, 0, true },
- { "kfuse", NULL, 0, true },
- { "fuse", NULL, 0, true },
{ "pll_u", NULL, 480000000, false },
{ "sdmmc1", "pll_p", 48000000, false},
{ "sdmmc3", "pll_p", 48000000, false},
{ "sdmmc4", "pll_p", 48000000, false},
- { "pll_a", "pll_p_out1", 0, false},
- { "pll_a_out0", "pll_a", 0, false},
+ { "sbc1.sclk", NULL, 40000000, false},
+ { "sbc2.sclk", NULL, 40000000, false},
+ { "sbc3.sclk", NULL, 40000000, false},
+ { "sbc4.sclk", NULL, 40000000, false},
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ { "sbc5.sclk", NULL, 40000000, false},
+ { "sbc6.sclk", NULL, 40000000, false},
+ { "wake.sclk", NULL, 40000000, true },
{ "cbus", "pll_c", 416000000, false },
{ "pll_c_out1", "pll_c", 208000000, false },
{ "mselect", "pll_p", 102000000, true },
@@ -301,8 +300,6 @@ void tegra_init_cache(bool init)
{
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
u32 aux_ctrl;
- u32 speedo;
- u32 tmp;
#ifdef CONFIG_TRUSTED_FOUNDATIONS
/* issue the SMC to enable the L2 */
@@ -329,6 +326,8 @@ void tegra_init_cache(bool init)
writel(0x221, p + L2X0_TAG_LATENCY_CTRL);
writel(0x221, p + L2X0_DATA_LATENCY_CTRL);
} else {
+ u32 speedo;
+
/* relax l2-cache latency for speedos 4,5,6 (T33's chips) */
speedo = tegra_cpu_speedo_id();
if (speedo == 4 || speedo == 5 || speedo == 6 ||
@@ -345,12 +344,15 @@ void tegra_init_cache(bool init)
writel(0x770, p + L2X0_DATA_LATENCY_CTRL);
#endif
#endif
+ writel(0x3, p + L2X0_POWER_CTRL);
aux_ctrl = readl(p + L2X0_CACHE_TYPE);
aux_ctrl = (aux_ctrl & 0x700) << (17-8);
aux_ctrl |= 0x7C000001;
if (init) {
l2x0_init(p, aux_ctrl, 0x8200c3fe);
} else {
+ u32 tmp;
+
tmp = aux_ctrl;
aux_ctrl = readl(p + L2X0_AUX_CTRL);
aux_ctrl &= 0x8200c3fe;
@@ -711,6 +713,22 @@ int tegra_get_modem_id(void)
__setup("modem_id=", tegra_modem_id);
+static int __init tegra_commchip_id(char *id)
+{
+ char *p = id;
+
+ if (get_option(&p, &commchip_id) != 1)
+ return 0;
+ return 1;
+}
+
+int tegra_get_commchip_id(void)
+{
+ return commchip_id;
+}
+
+__setup("commchip_id=", tegra_commchip_id);
+
/*
* Tegra has a protected aperture that prevents access by most non-CPU
* memory masters to addresses above the aperture value. Enabling it
@@ -778,28 +796,9 @@ out:
iounmap(to_io);
}
-#ifdef CONFIG_TEGRA_SMMU_BASE_AT_E0000000
-#define FORCE_SMMU_BASE_FOR_TEGRA3_A01 1
-#else
-#define FORCE_SMMU_BASE_FOR_TEGRA3_A01 0
-#endif
-#if FORCE_SMMU_BASE_FOR_TEGRA3_A01 || \
- (defined(CONFIG_TEGRA_IOVMM_SMMU) && defined(CONFIG_ARCH_TEGRA_3x_SOC))
-/* Support for Tegra3 A01 chip mask that needs to have SMMU IOVA reside in
- * the upper half of 4GB IOVA space. A02 and after use the bottom 1GB and
- * do not need to reserve memory.
- */
-#define SUPPORT_SMMU_BASE_FOR_TEGRA3_A01
-#endif
-
void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
unsigned long fb2_size)
{
-#ifdef SUPPORT_SMMU_BASE_FOR_TEGRA3_A01
- int smmu_reserved = 0;
- struct tegra_smmu_window *smmu_window = tegra_smmu_window(0);
-#endif
-
if (carveout_size) {
tegra_carveout_start = memblock_end_of_DRAM() - carveout_size;
if (memblock_remove(tegra_carveout_start, carveout_size)) {
@@ -845,33 +844,6 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
if (tegra_carveout_size && tegra_carveout_start < tegra_grhost_aperture)
tegra_grhost_aperture = tegra_carveout_start;
-#ifdef SUPPORT_SMMU_BASE_FOR_TEGRA3_A01
- if (!smmu_window) {
- pr_err("No SMMU resource\n");
- } else {
- size_t smmu_window_size;
-
- if (FORCE_SMMU_BASE_FOR_TEGRA3_A01 ||
- (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3 &&
- tegra_get_revision() == TEGRA_REVISION_A01)) {
- smmu_window->start = TEGRA_SMMU_BASE_TEGRA3_A01;
- smmu_window->end = TEGRA_SMMU_BASE_TEGRA3_A01 +
- TEGRA_SMMU_SIZE_TEGRA3_A01 - 1;
- }
- smmu_window_size = smmu_window->end + 1 - smmu_window->start;
- if (smmu_window->start >= 0x80000000) {
- if (memblock_reserve(smmu_window->start,
- smmu_window_size))
- pr_err(
- "Failed to reserve SMMU I/O VA window %08lx@%08lx\n",
- (unsigned long)smmu_window_size,
- (unsigned long)smmu_window->start);
- else
- smmu_reserved = 1;
- }
- }
-#endif
-
if (tegra_lp0_vec_size &&
(tegra_lp0_vec_start < memblock_end_of_DRAM())) {
if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size)) {
@@ -925,12 +897,6 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
tegra_vpr_start,
tegra_vpr_size ?
tegra_vpr_start + tegra_vpr_size - 1 : 0);
-
-#ifdef SUPPORT_SMMU_BASE_FOR_TEGRA3_A01
- if (smmu_reserved)
- pr_info("SMMU: %08lx - %08lx\n",
- smmu_window->start, smmu_window->end);
-#endif
}
static struct resource ram_console_resources[] = {
@@ -988,118 +954,53 @@ void __init tegra_release_bootloader_fb(void)
}
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
-static char cpufreq_gov_default[32];
-static char *cpufreq_gov_conservative = "conservative";
-static char *cpufreq_sysfs_place_holder="/sys/devices/system/cpu/cpu%i/cpufreq/scaling_governor";
-static char *cpufreq_gov_conservative_param="/sys/devices/system/cpu/cpufreq/conservative/%s";
+char cpufreq_default_gov[CONFIG_NR_CPUS][MAX_GOV_NAME_LEN];
+char *cpufreq_conservative_gov = "conservative";
-static void cpufreq_set_governor(char *governor)
+void cpufreq_store_default_gov(void)
{
- struct file *scaling_gov = NULL;
- mm_segment_t old_fs;
- char buf[128];
- int i = 0;
- loff_t offset = 0;
-
- if (governor == NULL)
- return;
+ unsigned int cpu;
+ struct cpufreq_policy *policy;
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-#ifndef CONFIG_TEGRA_AUTO_HOTPLUG
- for_each_online_cpu(i)
-#endif
- {
- sprintf(buf, cpufreq_sysfs_place_holder, i);
- scaling_gov = filp_open(buf, O_RDWR, 0);
- if (scaling_gov != NULL) {
- if (scaling_gov->f_op != NULL &&
- scaling_gov->f_op->write != NULL)
- scaling_gov->f_op->write(scaling_gov,
- governor,
- strlen(governor),
- &offset);
- else
- pr_err("f_op might be null\n");
-
- filp_close(scaling_gov, NULL);
- } else {
- pr_err("%s. Can't open %s\n", __func__, buf);
+ for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
+ policy = cpufreq_cpu_get(cpu);
+ if (policy) {
+ sprintf(cpufreq_default_gov[cpu], "%s",
+ policy->governor->name);
+ cpufreq_cpu_put(policy);
}
}
- set_fs(old_fs);
}
-void cpufreq_save_default_governor(void)
+int cpufreq_change_gov(char *target_gov)
{
- struct file *scaling_gov = NULL;
- mm_segment_t old_fs;
- char buf[128];
- loff_t offset = 0;
-
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- buf[127] = 0;
- sprintf(buf, cpufreq_sysfs_place_holder,0);
- scaling_gov = filp_open(buf, O_RDONLY, 0);
- if (scaling_gov != NULL) {
- if (scaling_gov->f_op != NULL &&
- scaling_gov->f_op->read != NULL)
- scaling_gov->f_op->read(scaling_gov,
- cpufreq_gov_default,
- 32,
- &offset);
- else
- pr_err("f_op might be null\n");
+ unsigned int cpu = 0;
- filp_close(scaling_gov, NULL);
- } else {
- pr_err("%s. Can't open %s\n", __func__, buf);
- }
- set_fs(old_fs);
-}
-
-void cpufreq_restore_default_governor(void)
-{
- cpufreq_set_governor(cpufreq_gov_default);
+#ifndef CONFIG_TEGRA_AUTO_HOTPLUG
+ for_each_online_cpu(cpu)
+#endif
+ return cpufreq_set_gov(target_gov, cpu);
}
-void cpufreq_set_conservative_governor_param(char *name, int value)
+int cpufreq_restore_default_gov(void)
{
- struct file *gov_param = NULL;
- mm_segment_t old_fs;
- static char buf[128], param_value[8];
- loff_t offset = 0;
-
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- sprintf(param_value, "%d", value);
- sprintf(buf, cpufreq_gov_conservative_param, name);
- gov_param = filp_open(buf, O_RDWR, 0);
- if (gov_param != NULL) {
- if (gov_param->f_op != NULL &&
- gov_param->f_op->write != NULL)
- gov_param->f_op->write(gov_param,
- param_value,
- strlen(param_value),
- &offset);
- else
- pr_err("f_op might be null\n");
+ int ret = 0;
+ unsigned int cpu;
- filp_close(gov_param, NULL);
- } else {
- pr_err("%s. Can't open %s\n", __func__, buf);
+ for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
+ if (strlen((const char *)&cpufreq_default_gov[cpu])) {
+ ret = cpufreq_set_gov(cpufreq_default_gov[cpu], cpu);
+ if (ret < 0)
+ /* Unable to restore gov for the cpu as
+ * It was online on suspend and becomes
+ * offline on resume.
+ */
+ pr_info("Unable to restore gov:%s for cpu:%d,"
+ , cpufreq_default_gov[cpu]
+ , cpu);
+ }
+ cpufreq_default_gov[cpu][0] = '\0';
}
- set_fs(old_fs);
-}
-
-void cpufreq_set_conservative_governor(void)
-{
- cpufreq_set_governor(cpufreq_gov_conservative);
+ return ret;
}
#endif /* CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND */
diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c
index d17e79c22bdf..86a0b1364b3d 100644
--- a/arch/arm/mach-tegra/cpu-tegra3.c
+++ b/arch/arm/mach-tegra/cpu-tegra3.c
@@ -147,9 +147,12 @@ static int hp_state_set(const char *arg, const struct kernel_param *kp)
if (ret == 0) {
if ((hp_state == TEGRA_HP_DISABLED) &&
- (old_state != TEGRA_HP_DISABLED))
+ (old_state != TEGRA_HP_DISABLED)) {
+ mutex_unlock(tegra3_cpu_lock);
+ cancel_delayed_work_sync(&hotplug_work);
+ mutex_lock(tegra3_cpu_lock);
pr_info("Tegra auto-hotplug disabled\n");
- else if (hp_state != TEGRA_HP_DISABLED) {
+ } else if (hp_state != TEGRA_HP_DISABLED) {
if (old_state == TEGRA_HP_DISABLED) {
pr_info("Tegra auto-hotplug enabled\n");
hp_init_stats();
@@ -324,7 +327,10 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
if (!is_g_cluster_present())
return;
- if (suspend && (hp_state != TEGRA_HP_DISABLED)) {
+ if (hp_state == TEGRA_HP_DISABLED)
+ return;
+
+ if (suspend) {
hp_state = TEGRA_HP_IDLE;
/* Switch to G-mode if suspend rate is high enough */
@@ -357,8 +363,6 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
}
switch (hp_state) {
- case TEGRA_HP_DISABLED:
- break;
case TEGRA_HP_IDLE:
if (cpu_freq > top_freq) {
hp_state = TEGRA_HP_UP;
diff --git a/arch/arm/mach-tegra/cpuidle-t2.c b/arch/arm/mach-tegra/cpuidle-t2.c
index d7b787bcac3b..ff6c320dd11c 100644
--- a/arch/arm/mach-tegra/cpuidle-t2.c
+++ b/arch/arm/mach-tegra/cpuidle-t2.c
@@ -40,7 +40,6 @@
#include <linux/tick.h>
#include <asm/cpu_pm.h>
-#include <asm/suspend.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
@@ -50,6 +49,7 @@
#include "pm.h"
#include "sleep.h"
#include "timer.h"
+#include "dvfs.h"
static struct {
unsigned int cpu_ready_count[2];
@@ -222,6 +222,7 @@ static int tegra2_idle_lp2_cpu_0(struct cpuidle_device *dev,
idle_stats.tear_down_count++;
entry_time = ktime_get();
+ tegra_dvfs_rail_off(tegra_cpu_rail, entry_time);
if (request > state->target_residency) {
s64 sleep_time = request - tegra_lp2_exit_latency;
@@ -248,6 +249,8 @@ static int tegra2_idle_lp2_cpu_0(struct cpuidle_device *dev,
}
exit_time = ktime_get();
+ tegra_dvfs_rail_on(tegra_cpu_rail, exit_time);
+
if (sleep_completed) {
/*
* Stayed in LP2 for the full time until the next tick,
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c
index 9a19a8a4260c..c6a50a542d8c 100644
--- a/arch/arm/mach-tegra/cpuidle-t3.c
+++ b/arch/arm/mach-tegra/cpuidle-t3.c
@@ -43,7 +43,6 @@
#include <asm/cpu_pm.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
-#include <asm/suspend.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
@@ -378,7 +377,7 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
tegra_cpu_wake_by_time[dev->cpu] = ktime_to_us(entry_time) + request;
smp_wmb();
- cpu_suspend(0, tegra3_sleep_cpu_secondary_finish);
+ tegra3_sleep_cpu_secondary(PLAT_PHYS_OFFSET - PAGE_OFFSET);
tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX;
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 202c767550e8..2a4f94c4e22d 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -1232,8 +1232,8 @@ static struct fsl_usb2_platform_data tegra_udc_pdata = {
};
struct platform_device tegra_udc_device = {
- .name = "fsl-tegra-udc",
- .id = -1,
+ .name = "tegra-udc",
+ .id = 0,
.dev = {
.dma_mask = &tegra_udc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index 66f9c24a946c..e4fe67fcba95 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -394,7 +394,8 @@ skip_status:
spin_unlock_irqrestore(&ch->lock, irq_flags);
/* Callback should be called without any lock */
- req->complete(req);
+ if(req->complete)
+ req->complete(req);
return 0;
}
EXPORT_SYMBOL(tegra_dma_dequeue_req);
@@ -678,6 +679,12 @@ void tegra_dma_free_channel(struct tegra_dma_channel *ch)
}
EXPORT_SYMBOL(tegra_dma_free_channel);
+int tegra_dma_get_channel_id(struct tegra_dma_channel *ch)
+{
+ return ch->id;
+}
+EXPORT_SYMBOL(tegra_dma_get_channel_id);
+
static bool tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
struct tegra_dma_req *req)
{
@@ -751,7 +758,10 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
u32 apb_ptr;
u32 csr;
- csr = CSR_IE_EOC | CSR_FLOW;
+ csr = CSR_FLOW;
+ if (req->complete || req->threshold)
+ csr |= CSR_IE_EOC;
+
ahb_seq = AHB_SEQ_INTR_ENB;
switch (req->req_sel) {
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index eaecf425fe87..a53a04ba95a2 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -21,7 +21,7 @@
#ifndef _TEGRA_DVFS_H_
#define _TEGRA_DVFS_H_
-#define MAX_DVFS_FREQS 18
+#define MAX_DVFS_FREQS 20
#define DVFS_RAIL_STATS_TOP_BIN 40
struct clk;
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index d9fe1b02d0e6..6df9da994fb9 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/fuse.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010-2011 NVIDIA Corp.
+ * Copyright (C) 2010-2012 NVIDIA Corp.
*
* Author:
* Colin Cross <ccross@android.com>
@@ -70,8 +70,6 @@ struct tegra_id {
};
static struct tegra_id tegra_id;
-static unsigned int tegra_chip_id;
-static unsigned int tegra_chip_rev;
static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_UNKNOWN] = "unknown",
@@ -343,19 +341,6 @@ static enum tegra_revision tegra_decode_revision(const struct tegra_id *id)
revision = tegra_chip_revisions[i].revision;
break;
}
-
-#elif defined(CONFIG_TEGRA_FPGA_PLATFORM)
- if ((id->chipid & 0xf0) == TEGRA_CHIPID_TEGRA3) {
- if ((id->major == 0) && (id->minor == 1)) {
- unsigned int patch = id->patch & 0xF;
- if ((id->netlist == 12) && (patch == 12))
- revision = TEGRA_REVISION_A01;
- else if ((id->netlist == 12) && (patch > 12))
- revision = TEGRA_REVISION_A02;
- else if (id->netlist > 12)
- revision = TEGRA_REVISION_A02;
- }
- }
#endif
return revision;
@@ -396,66 +381,37 @@ static void tegra_get_tegraid_from_hw(void)
enum tegra_chipid tegra_get_chipid(void)
{
- if (tegra_id.chipid == TEGRA_CHIPID_UNKNOWN) {
- /* Boot loader did not pass a valid chip ID.
- * Get it from hardware */
+ if (tegra_id.chipid == TEGRA_CHIPID_UNKNOWN)
tegra_get_tegraid_from_hw();
- }
return tegra_id.chipid;
}
enum tegra_revision tegra_get_revision(void)
{
- if (tegra_id.chipid == TEGRA_CHIPID_UNKNOWN) {
- /* Boot loader did not pass a valid chip ID.
- * Get it from hardware */
+ if (tegra_id.chipid == TEGRA_CHIPID_UNKNOWN)
tegra_get_tegraid_from_hw();
- }
return tegra_id.revision;
}
-static char chippriv[16]; /* Permanent buffer for private string */
-static int __init tegra_bootloader_tegraid(char *str)
-{
- u32 id[5];
- int i = 0;
- char *priv = NULL;
-
- do {
- id[i++] = simple_strtoul(str, &str, 16);
- } while (*str++ && i < ARRAY_SIZE(id));
-
- if (*(str - 1) == '.') {
- strncpy(chippriv, str, sizeof(chippriv) - 1);
- priv = chippriv;
- if (strlen(str) > sizeof(chippriv) - 1)
- pr_err("### tegraid.priv in kernel arg truncated\n");
- }
-
- while (i < ARRAY_SIZE(id))
- id[i++] = 0;
-
- tegra_set_tegraid(id[0], id[1], id[2], id[3], id[4], priv);
- return 0;
-}
-
-static unsigned int get_chip_id(char *val, struct kernel_param *kp)
+static int get_chip_id(char *val, const struct kernel_param *kp)
{
- tegra_chip_id = (unsigned int)tegra_get_chipid();
return param_get_uint(val, kp);
}
-static unsigned int get_chip_rev(char *val, struct kernel_param *kp)
+
+static int get_revision(char *val, const struct kernel_param *kp)
{
- tegra_chip_rev = (unsigned int)tegra_get_revision();
return param_get_uint(val, kp);
}
-module_param_call(tegra_chip_id, NULL, get_chip_id, &tegra_chip_id, 0444);
-__MODULE_PARM_TYPE(tegra_chip_id, "uint");
-module_param_call(tegra_chip_rev, NULL, get_chip_rev, &tegra_chip_rev, 0444);
-__MODULE_PARM_TYPE(tegra_chip_rev, "uint");
+static struct kernel_param_ops tegra_chip_id_ops = {
+ .get = get_chip_id,
+};
+
+static struct kernel_param_ops tegra_revision_ops = {
+ .get = get_revision,
+};
-/* tegraid=chipid.major.minor.netlist.patch[.priv] */
-early_param("tegraid", tegra_bootloader_tegraid);
+module_param_cb(tegra_chip_id, &tegra_chip_id_ops, &tegra_id.chipid, 0444);
+module_param_cb(tegra_chip_rev, &tegra_revision_ops, &tegra_id.revision, 0444);
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index 219b7641a40f..4e28a558cc38 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -66,7 +66,7 @@ ENTRY(tegra_resume)
cpu_id r0
cmp r0, #0 @ CPU0?
- bne cpu_resume @ no
+ bne tegra_cpu_resume_phys @ no
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
@ Clear the flow controller flags for this CPU.
@@ -83,7 +83,9 @@ ENTRY(tegra_resume)
ldr r1, [r0]
orr r1, r1, #1
#if defined(CONFIG_HAVE_ARM_SCU)
- orr r1, r1, #(1 << 3) @ Enabled SCU speculative line fill.
+ orr r1, r1, #(1 << 3) @ Enable SCU speculative line fill.
+ orr r1, r1, #(1 << 5) @ Enable IC standby.
+ orr r1, r1, #(1 << 6) @ Enable SCU standby.
#endif
str r1, [r0]
@@ -92,7 +94,7 @@ ENTRY(tegra_resume)
bl tegra_generic_smc
#endif
- b cpu_resume
+ b tegra_cpu_resume_phys
ENDPROC(tegra_resume)
#endif
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index d4f63afa9d99..ab3d4e920f46 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -6,7 +6,7 @@
* Author:
* Erik Gilling <konkers@google.com>
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (C) 2010-2011 NVIDIA Corporation
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -426,6 +426,7 @@ struct tegra_dc_win {
unsigned out_w;
unsigned out_h;
unsigned z;
+ u8 global_alpha;
struct tegra_dc_csc csc;
@@ -505,6 +506,8 @@ struct tegra_dc_platform_data {
struct tegra_dc *tegra_dc_get_dc(unsigned idx);
struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win);
bool tegra_dc_get_connected(struct tegra_dc *);
+bool tegra_dc_hpd(struct tegra_dc *dc);
+
void tegra_dc_blank(struct tegra_dc *dc);
@@ -523,8 +526,6 @@ int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode);
struct fb_videomode;
-int tegra_dc_to_fb_videomode(struct fb_videomode *fbmode,
- const struct tegra_dc_mode *mode);
int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode,
bool stereo_mode);
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
index c6617e95c1af..a0423e950690 100644
--- a/arch/arm/mach-tegra/include/mach/dma.h
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -190,6 +190,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode,
const char namefmt[], ...);
void tegra_dma_free_channel(struct tegra_dma_channel *ch);
+int tegra_dma_get_channel_id(struct tegra_dma_channel *ch);
/*
* tegra_dma_cancel: Stop the dma and remove all request from pending request
* queue for transfer.
diff --git a/arch/arm/mach-tegra/include/mach/hdmi-audio.h b/arch/arm/mach-tegra/include/mach/hdmi-audio.h
index 7d760690081a..35555504037a 100644
--- a/arch/arm/mach-tegra/include/mach/hdmi-audio.h
+++ b/arch/arm/mach-tegra/include/mach/hdmi-audio.h
@@ -42,5 +42,6 @@ enum {
int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_source);
int tegra_hdmi_setup_hda_presence(void);
+int tegra_hdmi_audio_null_sample_inject(bool on);
#endif /* __MACH_TEGRA_HDMI_AUDIO_H */
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
index 2b091bf83f39..c6847fb78bab 100644
--- a/arch/arm/mach-tegra/include/mach/io.h
+++ b/arch/arm/mach-tegra/include/mach/io.h
@@ -82,6 +82,14 @@
#define IO_PPCS_VIRT 0xFE100000
#define IO_PPCS_SIZE SZ_1M
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define IO_PCIE_PHYS 0x80000000
+#else
+#define IO_PCIE_PHYS 0x00000000
+#endif
+#define IO_PCIE_VIRT 0xFB000000
+#define IO_PCIE_SIZE (SZ_16M * 3)
+
#define IO_TO_VIRT_BETWEEN(p, st, sz) ((p) >= (st) && (p) < ((st) + (sz)))
#define IO_TO_VIRT_XLATE(p, pst, vst) (((p) - (pst) + (vst)))
@@ -102,6 +110,8 @@
IO_TO_VIRT_XLATE((n), IO_SDMMC_PHYS, IO_SDMMC_VIRT) : \
IO_TO_VIRT_BETWEEN((n), IO_PPCS_PHYS, IO_PPCS_SIZE) ? \
IO_TO_VIRT_XLATE((n), IO_PPCS_PHYS, IO_PPCS_VIRT) : \
+ IO_TO_VIRT_BETWEEN((n), IO_PCIE_PHYS, IO_PCIE_SIZE) ? \
+ IO_TO_VIRT_XLATE((n), IO_PCIE_PHYS, IO_PCIE_VIRT) : \
0)
#ifndef __ASSEMBLER__
diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h
index b48a92887070..5dc8cd2ddf76 100644
--- a/arch/arm/mach-tegra/include/mach/sdhci.h
+++ b/arch/arm/mach-tegra/include/mach/sdhci.h
@@ -28,6 +28,7 @@ struct tegra_sdhci_platform_data {
int pm_flags;
int pm_caps;
unsigned int max_clk_limit;
+ unsigned int ddr_clk_limit;
unsigned int tap_delay;
struct mmc_platform_data mmc_data;
};
diff --git a/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h
index bfd61c460051..6bea4e50b915 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h
@@ -37,6 +37,12 @@ struct codec_info_s {
char *name; /* Name of the Codec-Dai-Link */
enum i2s_data_format i2s_format;
int master; /* Codec is Master or Slave */
+ /* TDM format setttings */
+ int num_slots; /* Number of TDM slots */
+ int slot_width; /* Width of each slot */
+ int rx_mask; /* Number of Rx Enabled slots */
+ int tx_mask; /* Number of Tx Enabled slots */
+
};
struct tegra_p1852_platform_data {
diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h
index ab7b34492d9e..67586224cead 100644
--- a/arch/arm/mach-tegra/include/mach/thermal.h
+++ b/arch/arm/mach-tegra/include/mach/thermal.h
@@ -19,19 +19,17 @@
/* All units in millicelsius */
struct tegra_thermal_data {
- long temp_throttle;
long temp_shutdown;
long temp_offset;
#ifdef CONFIG_TEGRA_EDP_LIMITS
long edp_offset;
long hysteresis_edp;
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ long temp_throttle;
int tc1;
int tc2;
long passive_delay;
-#else
- long hysteresis_throttle;
#endif
};
diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c
index 47279e1d5eb8..bcd10843a99d 100644
--- a/arch/arm/mach-tegra/io.c
+++ b/arch/arm/mach-tegra/io.c
@@ -80,6 +80,12 @@ static struct map_desc tegra_io_desc[] __initdata = {
.pfn = __phys_to_pfn(IO_PPCS_PHYS),
.length = IO_PPCS_SIZE,
.type = MT_DEVICE,
+ },
+ {
+ .virtual = IO_PCIE_VIRT,
+ .pfn = __phys_to_pfn(IO_PCIE_PHYS),
+ .length = IO_PCIE_SIZE,
+ .type = MT_DEVICE,
}
};
diff --git a/arch/arm/mach-tegra/iovmm-smmu.c b/arch/arm/mach-tegra/iovmm-smmu.c
index 170afd15f1c3..6cdeb744a04c 100644
--- a/arch/arm/mach-tegra/iovmm-smmu.c
+++ b/arch/arm/mach-tegra/iovmm-smmu.c
@@ -310,10 +310,14 @@ struct smmu_device {
/*
* Register image savers for suspend/resume
*/
- unsigned long translation_enable_0_0;
- unsigned long translation_enable_1_0;
- unsigned long translation_enable_2_0;
- unsigned long asid_security_0;
+ unsigned long config_0; /* Secure reg */
+ unsigned long tlb_config_0;
+ unsigned long ptc_config_0;
+ unsigned long ptb_asid_0;
+ unsigned long translation_enable_0_0; /* Secure reg */
+ unsigned long translation_enable_1_0; /* Secure reg */
+ unsigned long translation_enable_2_0; /* Secure reg */
+ unsigned long asid_security_0; /* Secure reg */
unsigned long lowest_asid; /* Variables for hardware testing */
unsigned long debug_asid;
@@ -335,13 +339,13 @@ struct smmu_device {
* must have these read-back to ensure the APB/AHB bus transaction is
* complete before initiating activity on the PPSB block.
*/
-#define FLUSH_SMMU_REGS(smmu) (void)readl((smmu)->regs + MC_SMMU_CONFIG_0)
+#define FLUSH_SMMU_REGS(smmu) (void)readl((smmu)->regs + MC_SMMU_PTB_DATA_0)
/*
* Flush all TLB entries and all PTC entries
* Caller must lock smmu
*/
-static void smmu_flush_regs(struct smmu_device *smmu, int enable)
+static void smmu_flush_regs(struct smmu_device *smmu)
{
writel(MC_SMMU_PTC_FLUSH_0_PTC_FLUSH_TYPE_ALL,
smmu->regs + MC_SMMU_PTC_FLUSH_0);
@@ -349,10 +353,6 @@ static void smmu_flush_regs(struct smmu_device *smmu, int enable)
writel(MC_SMMU_TLB_FLUSH_0_TLB_FLUSH_VA_MATCH_ALL |
MC_SMMU_TLB_FLUSH_0_TLB_FLUSH_ASID_MATCH_disable,
smmu->regs + MC_SMMU_TLB_FLUSH_0);
-
- if (enable)
- writel(MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE,
- smmu->regs + MC_SMMU_CONFIG_0);
FLUSH_SMMU_REGS(smmu);
}
@@ -388,14 +388,14 @@ static void smmu_setup_regs(struct smmu_device *smmu)
smmu->regs + MC_SMMU_TRANSLATION_ENABLE_1_0);
writel(smmu->translation_enable_2_0,
smmu->regs + MC_SMMU_TRANSLATION_ENABLE_2_0);
- writel(smmu->asid_security_0,
- smmu->regs + MC_SMMU_ASID_SECURITY_0);
- writel(MC_SMMU_TLB_CONFIG_0_RESET_VAL,
- smmu->regs + MC_SMMU_TLB_CONFIG_0);
- writel(MC_SMMU_PTC_CONFIG_0_RESET_VAL,
- smmu->regs + MC_SMMU_PTC_CONFIG_0);
-
- smmu_flush_regs(smmu, 1);
+ writel(smmu->asid_security_0, smmu->regs + MC_SMMU_ASID_SECURITY_0);
+ writel(smmu->ptb_asid_0, smmu->regs + MC_SMMU_PTB_ASID_0);
+ writel(smmu->ptc_config_0, smmu->regs + MC_SMMU_PTC_CONFIG_0);
+ writel(smmu->tlb_config_0, smmu->regs + MC_SMMU_TLB_CONFIG_0);
+ writel(smmu->config_0, smmu->regs + MC_SMMU_CONFIG_0);
+
+ smmu_flush_regs(smmu);
+
writel(
readl(smmu->regs_ahbarb + AHB_ARBITRATION_XBAR_CTRL_0) |
(AHB_ARBITRATION_XBAR_CTRL_0_SMMU_INIT_DONE_DONE <<
@@ -408,6 +408,10 @@ static int smmu_suspend(struct tegra_iovmm_device *dev)
struct smmu_device *smmu =
container_of(dev, struct smmu_device, iovmm_dev);
+ smmu->config_0 = readl(smmu->regs + MC_SMMU_CONFIG_0);
+ smmu->tlb_config_0 = readl(smmu->regs + MC_SMMU_TLB_CONFIG_0);
+ smmu->ptc_config_0 = readl(smmu->regs + MC_SMMU_PTC_CONFIG_0);
+ smmu->ptb_asid_0 = readl(smmu->regs + MC_SMMU_PTB_ASID_0);
smmu->translation_enable_0_0 =
readl(smmu->regs + MC_SMMU_TRANSLATION_ENABLE_0_0);
smmu->translation_enable_1_0 =
@@ -691,10 +695,8 @@ static void smmu_unmap(struct tegra_iovmm_domain *domain,
flush_ptc_and_tlb(as->smmu, as, addr, pte,
page, 0);
kunmap(page);
- if (!--(*pte_counter) && decommit) {
+ if (!--(*pte_counter) && decommit)
free_ptbl(as, addr);
- smmu_flush_regs(as->smmu, 0);
- }
}
}
addr += SMMU_PAGE_SIZE;
@@ -703,7 +705,7 @@ static void smmu_unmap(struct tegra_iovmm_domain *domain,
}
static void smmu_map_pfn(struct tegra_iovmm_domain *domain,
- struct tegra_iovmm_area *iovma, tegra_iovmm_addr_t addr,
+ struct tegra_iovmm_area *iovma, unsigned long addr,
unsigned long pfn)
{
struct smmu_as *as = container_of(domain, struct smmu_as, domain);
@@ -966,10 +968,14 @@ static int smmu_probe(struct platform_device *pdev)
goto fail;
}
+ smmu->config_0 = MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE;
+ smmu->tlb_config_0 = MC_SMMU_TLB_CONFIG_0_RESET_VAL;
+ smmu->ptc_config_0 = MC_SMMU_PTC_CONFIG_0_RESET_VAL;
+ smmu->ptb_asid_0 = 0;
smmu->translation_enable_0_0 = ~0;
smmu->translation_enable_1_0 = ~0;
smmu->translation_enable_2_0 = ~0;
- smmu->asid_security_0 = 0;
+ smmu->asid_security_0 = 0;
memcpy(smmu->hwc_state, smmu_hwc_state_init, sizeof(smmu->hwc_state));
diff --git a/arch/arm/mach-tegra/p852/board-p852-panel.c b/arch/arm/mach-tegra/p852/board-p852-panel.c
index c47032dd4f0a..bcf9f4af76cf 100644
--- a/arch/arm/mach-tegra/p852/board-p852-panel.c
+++ b/arch/arm/mach-tegra/p852/board-p852-panel.c
@@ -25,7 +25,7 @@
#include <linux/nvhost.h>
#include <linux/platform_device.h>
#include <asm/mach-types.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index b98d4892b5ee..1c4ee1b1f5ce 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -540,7 +540,7 @@ static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
-static void __init tegra_pcie_preinit(void)
+static void tegra_pcie_preinit(void)
{
pcie_io_space.name = "PCIe I/O Space";
pcie_io_space.start = PCIBIOS_MIN_IO;
@@ -1099,13 +1099,14 @@ static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
}
retry:
- /* Pulse the PEX reset */
- reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
- afi_writel(reg, reset_reg);
- reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
- afi_writel(reg, reset_reg);
+ if (--retries) {
+ /* Pulse the PEX reset */
+ reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+ reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+ }
- retries--;
} while (retries);
return false;
@@ -1201,9 +1202,13 @@ static int tegra_pci_probe(struct platform_device *pdev)
static int tegra_pci_suspend(struct device *dev)
{
+ int ret = 0;
struct pci_dev *pdev = NULL;
int i, size, ndev = 0;
+ if (!tegra_pcie.num_ports)
+ return ret;
+
for_each_pci_dev(pdev) {
/* save state of pcie devices before powering off regulators */
pci_save_state(pdev);
@@ -1243,10 +1248,12 @@ static int tegra_pci_resume_noirq(struct device *dev)
static int tegra_pci_resume(struct device *dev)
{
- int ret;
+ int ret = 0;
int i, size, ndev = 0;
struct pci_dev *pdev = NULL;
+ if (!tegra_pcie.num_ports)
+ return ret;
ret = tegra_pcie_power_on();
tegra_pcie_enable_controller();
tegra_pcie_setup_translations();
diff --git a/arch/arm/mach-tegra/pinmux-t2-tables.c b/arch/arm/mach-tegra/pinmux-t2-tables.c
index 3a39f45cb57e..32e55421c583 100644
--- a/arch/arm/mach-tegra/pinmux-t2-tables.c
+++ b/arch/arm/mach-tegra/pinmux-t2-tables.c
@@ -195,9 +195,9 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
PINGROUP(LM0, PW0, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, RSVD4, 0x1C, 24, 0x90, 26, 0xAC, 22),\
PINGROUP(LM1, PW1, LCD, DISPLAYA, DISPLAYB, RSVD, CRT, RSVD3, 0x1C, 25, 0x90, 28, 0xAC, 22),\
PINGROUP(LPP, PM7, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 8, 0x98, 14, 0xAC, 18),\
- PINGROUP(LPW0, PB2, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 3, 0x90, 0, 0xAC, 20),\
+ PINGROUP(LPW0, PB2, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYB, 0x20, 3, 0x90, 0, 0xAC, 20),\
PINGROUP(LPW1, PC1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 4, 0x90, 2, 0xAC, 20),\
- PINGROUP(LPW2, PC6, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 5, 0x90, 4, 0xAC, 20),\
+ PINGROUP(LPW2, PC6, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYB, 0x20, 5, 0x90, 4, 0xAC, 20),\
PINGROUP(LSC0, PB3, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 27, 0x90, 18, 0xAC, 22),\
PINGROUP(LSC1, PZ3, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 28, 0x90, 20, 0xAC, 20),\
PINGROUP(LSCK, PZ4, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 29, 0x90, 16, 0xAC, 20),\
diff --git a/arch/arm/mach-tegra/pinmux-t3-tables.c b/arch/arm/mach-tegra/pinmux-t3-tables.c
index 282a34bdd0d3..5e50fede625d 100644
--- a/arch/arm/mach-tegra/pinmux-t3-tables.c
+++ b/arch/arm/mach-tegra/pinmux-t3-tables.c
@@ -140,166 +140,166 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
#define PINGROUPS \
/* NAME GPIO VDD f0 f1 f2 f3 fSafe io reg */\
- PINGROUP(ULPI_DATA0, PO1, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3000),\
- PINGROUP(ULPI_DATA1, PO2, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3004),\
- PINGROUP(ULPI_DATA2, PO3, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3008),\
- PINGROUP(ULPI_DATA3, PO4, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x300c),\
- PINGROUP(ULPI_DATA4, PO5, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3010),\
- PINGROUP(ULPI_DATA5, PO6, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3014),\
- PINGROUP(ULPI_DATA6, PO7, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3018),\
- PINGROUP(ULPI_DATA7, PO0, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x301c),\
- PINGROUP(ULPI_CLK, PY0, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3020),\
- PINGROUP(ULPI_DIR, PY1, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3024),\
- PINGROUP(ULPI_NXT, PY2, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3028),\
- PINGROUP(ULPI_STP, PY3, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x302c),\
- PINGROUP(DAP3_FS, PP0, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3030),\
- PINGROUP(DAP3_DIN, PP1, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3034),\
- PINGROUP(DAP3_DOUT, PP2, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3038),\
- PINGROUP(DAP3_SCLK, PP3, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x303c),\
+ PINGROUP(ULPI_DATA0, PO1, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x3000),\
+ PINGROUP(ULPI_DATA1, PO2, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x3004),\
+ PINGROUP(ULPI_DATA2, PO3, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x3008),\
+ PINGROUP(ULPI_DATA3, PO4, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x300c),\
+ PINGROUP(ULPI_DATA4, PO5, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x3010),\
+ PINGROUP(ULPI_DATA5, PO6, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x3014),\
+ PINGROUP(ULPI_DATA6, PO7, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x3018),\
+ PINGROUP(ULPI_DATA7, PO0, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x301c),\
+ PINGROUP(ULPI_CLK, PY0, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x3020),\
+ PINGROUP(ULPI_DIR, PY1, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x3024),\
+ PINGROUP(ULPI_NXT, PY2, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x3028),\
+ PINGROUP(ULPI_STP, PY3, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x302c),\
+ PINGROUP(DAP3_FS, PP0, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x3030),\
+ PINGROUP(DAP3_DIN, PP1, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x3034),\
+ PINGROUP(DAP3_DOUT, PP2, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x3038),\
+ PINGROUP(DAP3_SCLK, PP3, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x303c),\
PINGROUP(GPIO_PV0, PV0, BB, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3040),\
PINGROUP(GPIO_PV1, PV1, BB, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3044),\
- PINGROUP(SDMMC1_CLK, PZ0, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, RSVD, INPUT, 0x3048),\
- PINGROUP(SDMMC1_CMD, PZ1, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, RSVD, INPUT, 0x304c),\
- PINGROUP(SDMMC1_DAT3, PY4, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3050),\
- PINGROUP(SDMMC1_DAT2, PY5, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3054),\
- PINGROUP(SDMMC1_DAT1, PY6, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3058),\
- PINGROUP(SDMMC1_DAT0, PY7, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x305c),\
+ PINGROUP(SDMMC1_CLK, PZ0, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, SDMMC1, INPUT, 0x3048),\
+ PINGROUP(SDMMC1_CMD, PZ1, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, SDMMC1, INPUT, 0x304c),\
+ PINGROUP(SDMMC1_DAT3, PY4, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x3050),\
+ PINGROUP(SDMMC1_DAT2, PY5, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x3054),\
+ PINGROUP(SDMMC1_DAT1, PY6, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x3058),\
+ PINGROUP(SDMMC1_DAT0, PY7, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x305c),\
PINGROUP(GPIO_PV2, PV2, SDMMC1, OWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3060),\
PINGROUP(GPIO_PV3, PV3, SDMMC1, INVALID, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3064),\
- PINGROUP(CLK2_OUT, PW5, SDMMC1, EXTPERIPH2, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3068),\
- PINGROUP(CLK2_REQ, PCC5, SDMMC1, DAP, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x306c),\
- PINGROUP(LCD_PWR1, PC1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3070),\
- PINGROUP(LCD_PWR2, PC6, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3074),\
- PINGROUP(LCD_SDIN, PZ2, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, RSVD, OUTPUT, 0x3078),\
- PINGROUP(LCD_SDOUT, PN5, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x307c),\
- PINGROUP(LCD_WR_N, PZ3, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3080),\
- PINGROUP(LCD_CS0_N, PN4, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, RSVD, OUTPUT, 0x3084),\
- PINGROUP(LCD_DC0, PN6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3088),\
- PINGROUP(LCD_SCK, PZ4, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x308c),\
- PINGROUP(LCD_PWR0, PB2, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3090),\
- PINGROUP(LCD_PCLK, PB3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3094),\
- PINGROUP(LCD_DE, PJ1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3098),\
- PINGROUP(LCD_HSYNC, PJ3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x309c),\
- PINGROUP(LCD_VSYNC, PJ4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a0),\
- PINGROUP(LCD_D0, PE0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a4),\
- PINGROUP(LCD_D1, PE1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a8),\
- PINGROUP(LCD_D2, PE2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30ac),\
- PINGROUP(LCD_D3, PE3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b0),\
- PINGROUP(LCD_D4, PE4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b4),\
- PINGROUP(LCD_D5, PE5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b8),\
- PINGROUP(LCD_D6, PE6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30bc),\
- PINGROUP(LCD_D7, PE7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c0),\
- PINGROUP(LCD_D8, PF0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c4),\
- PINGROUP(LCD_D9, PF1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c8),\
- PINGROUP(LCD_D10, PF2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30cc),\
- PINGROUP(LCD_D11, PF3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d0),\
- PINGROUP(LCD_D12, PF4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d4),\
- PINGROUP(LCD_D13, PF5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d8),\
- PINGROUP(LCD_D14, PF6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30dc),\
- PINGROUP(LCD_D15, PF7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e0),\
- PINGROUP(LCD_D16, PM0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e4),\
- PINGROUP(LCD_D17, PM1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e8),\
- PINGROUP(LCD_D18, PM2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30ec),\
- PINGROUP(LCD_D19, PM3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f0),\
- PINGROUP(LCD_D20, PM4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f4),\
- PINGROUP(LCD_D21, PM5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f8),\
- PINGROUP(LCD_D22, PM6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30fc),\
- PINGROUP(LCD_D23, PM7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3100),\
- PINGROUP(LCD_CS1_N, PW0, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD2, RSVD, OUTPUT, 0x3104),\
- PINGROUP(LCD_M1, PW1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3108),\
- PINGROUP(LCD_DC1, PD2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x310c),\
+ PINGROUP(CLK2_OUT, PW5, SDMMC1, EXTPERIPH2, RSVD1, RSVD2, RSVD3, EXTPERIPH2, INPUT, 0x3068),\
+ PINGROUP(CLK2_REQ, PCC5, SDMMC1, DAP, RSVD1, RSVD2, RSVD3, DAP, INPUT, 0x306c),\
+ PINGROUP(LCD_PWR1, PC1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3070),\
+ PINGROUP(LCD_PWR2, PC6, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x3074),\
+ PINGROUP(LCD_SDIN, PZ2, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, DISPLAYA, OUTPUT, 0x3078),\
+ PINGROUP(LCD_SDOUT, PN5, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x307c),\
+ PINGROUP(LCD_WR_N, PZ3, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x3080),\
+ PINGROUP(LCD_CS0_N, PN4, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, DISPLAYA, OUTPUT, 0x3084),\
+ PINGROUP(LCD_DC0, PN6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3088),\
+ PINGROUP(LCD_SCK, PZ4, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x308c),\
+ PINGROUP(LCD_PWR0, PB2, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x3090),\
+ PINGROUP(LCD_PCLK, PB3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3094),\
+ PINGROUP(LCD_DE, PJ1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3098),\
+ PINGROUP(LCD_HSYNC, PJ3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x309c),\
+ PINGROUP(LCD_VSYNC, PJ4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30a0),\
+ PINGROUP(LCD_D0, PE0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30a4),\
+ PINGROUP(LCD_D1, PE1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30a8),\
+ PINGROUP(LCD_D2, PE2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30ac),\
+ PINGROUP(LCD_D3, PE3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30b0),\
+ PINGROUP(LCD_D4, PE4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30b4),\
+ PINGROUP(LCD_D5, PE5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30b8),\
+ PINGROUP(LCD_D6, PE6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30bc),\
+ PINGROUP(LCD_D7, PE7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30c0),\
+ PINGROUP(LCD_D8, PF0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30c4),\
+ PINGROUP(LCD_D9, PF1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30c8),\
+ PINGROUP(LCD_D10, PF2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30cc),\
+ PINGROUP(LCD_D11, PF3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30d0),\
+ PINGROUP(LCD_D12, PF4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30d4),\
+ PINGROUP(LCD_D13, PF5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30d8),\
+ PINGROUP(LCD_D14, PF6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30dc),\
+ PINGROUP(LCD_D15, PF7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30e0),\
+ PINGROUP(LCD_D16, PM0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30e4),\
+ PINGROUP(LCD_D17, PM1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30e8),\
+ PINGROUP(LCD_D18, PM2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30ec),\
+ PINGROUP(LCD_D19, PM3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30f0),\
+ PINGROUP(LCD_D20, PM4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30f4),\
+ PINGROUP(LCD_D21, PM5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30f8),\
+ PINGROUP(LCD_D22, PM6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30fc),\
+ PINGROUP(LCD_D23, PM7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3100),\
+ PINGROUP(LCD_CS1_N, PW0, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD2, DISPLAYA, OUTPUT, 0x3104),\
+ PINGROUP(LCD_M1, PW1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3108),\
+ PINGROUP(LCD_DC1, PD2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x310c),\
PINGROUP(HDMI_INT, PN7, LCD, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3110),\
- PINGROUP(DDC_SCL, PV4, LCD, I2C4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3114),\
- PINGROUP(DDC_SDA, PV5, LCD, I2C4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3118),\
- PINGROUP(CRT_HSYNC, PV6, LCD, CRT, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x311c),\
- PINGROUP(CRT_VSYNC, PV7, LCD, CRT, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3120),\
- PINGROUP(VI_D0, PT4, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3124),\
- PINGROUP(VI_D1, PD5, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3128),\
- PINGROUP(VI_D2, PL0, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x312c),\
- PINGROUP(VI_D3, PL1, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3130),\
- PINGROUP(VI_D4, PL2, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3134),\
- PINGROUP(VI_D5, PL3, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3138),\
- PINGROUP(VI_D6, PL4, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x313c),\
- PINGROUP(VI_D7, PL5, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3140),\
- PINGROUP(VI_D8, PL6, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3144),\
- PINGROUP(VI_D9, PL7, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3148),\
- PINGROUP(VI_D10, PT2, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x314c),\
- PINGROUP(VI_D11, PT3, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3150),\
- PINGROUP(VI_PCLK, PT0, VI, RSVD1, SDMMC2, VI, RSVD2, RSVD, INPUT, 0x3154),\
+ PINGROUP(DDC_SCL, PV4, LCD, I2C4, RSVD1, RSVD2, RSVD3, I2C4, INPUT, 0x3114),\
+ PINGROUP(DDC_SDA, PV5, LCD, I2C4, RSVD1, RSVD2, RSVD3, I2C4, INPUT, 0x3118),\
+ PINGROUP(CRT_HSYNC, PV6, LCD, CRT, RSVD1, RSVD2, RSVD3, CRT, INPUT, 0x311c),\
+ PINGROUP(CRT_VSYNC, PV7, LCD, CRT, RSVD1, RSVD2, RSVD3, CRT, INPUT, 0x3120),\
+ PINGROUP(VI_D0, PT4, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x3124),\
+ PINGROUP(VI_D1, PD5, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3128),\
+ PINGROUP(VI_D2, PL0, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x312c),\
+ PINGROUP(VI_D3, PL1, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3130),\
+ PINGROUP(VI_D4, PL2, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3134),\
+ PINGROUP(VI_D5, PL3, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3138),\
+ PINGROUP(VI_D6, PL4, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x313c),\
+ PINGROUP(VI_D7, PL5, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3140),\
+ PINGROUP(VI_D8, PL6, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3144),\
+ PINGROUP(VI_D9, PL7, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3148),\
+ PINGROUP(VI_D10, PT2, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x314c),\
+ PINGROUP(VI_D11, PT3, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x3150),\
+ PINGROUP(VI_PCLK, PT0, VI, RSVD1, SDMMC2, VI, RSVD2, VI, INPUT, 0x3154),\
PINGROUP(VI_MCLK, PT1, VI, INVALID, INVALID, INVALID, VI, RSVD, INPUT, 0x3158),\
- PINGROUP(VI_VSYNC, PD6, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x315c),\
- PINGROUP(VI_HSYNC, PD7, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3160),\
- PINGROUP(UART2_RXD, PC3, UART, IRDA, SPDIF, UARTA, SPI4, RSVD, INPUT, 0x3164),\
- PINGROUP(UART2_TXD, PC2, UART, IRDA, SPDIF, UARTA, SPI4, RSVD, INPUT, 0x3168),\
- PINGROUP(UART2_RTS_N, PJ6, UART, UARTA, UARTB, GMI, SPI4, RSVD, INPUT, 0x316c),\
- PINGROUP(UART2_CTS_N, PJ5, UART, UARTA, UARTB, GMI, SPI4, RSVD, INPUT, 0x3170),\
- PINGROUP(UART3_TXD, PW6, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x3174),\
- PINGROUP(UART3_RXD, PW7, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x3178),\
- PINGROUP(UART3_CTS_N, PA1, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x317c),\
- PINGROUP(UART3_RTS_N, PC0, UART, UARTC, PWM0, GMI, RSVD2, RSVD, INPUT, 0x3180),\
- PINGROUP(GPIO_PU0, PU0, UART, OWR, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3184),\
- PINGROUP(GPIO_PU1, PU1, UART, RSVD1, UARTA, GMI, RSVD2, RSVD, INPUT, 0x3188),\
- PINGROUP(GPIO_PU2, PU2, UART, RSVD1, UARTA, GMI, RSVD2, RSVD, INPUT, 0x318c),\
- PINGROUP(GPIO_PU3, PU3, UART, PWM0, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3190),\
- PINGROUP(GPIO_PU4, PU4, UART, PWM1, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3194),\
- PINGROUP(GPIO_PU5, PU5, UART, PWM2, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3198),\
- PINGROUP(GPIO_PU6, PU6, UART, PWM3, UARTA, GMI, RSVD1, RSVD, INPUT, 0x319c),\
- PINGROUP(GEN1_I2C_SDA, PC5, UART, I2C1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31a0),\
- PINGROUP(GEN1_I2C_SCL, PC4, UART, I2C1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31a4),\
- PINGROUP(DAP4_FS, PP4, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31a8),\
- PINGROUP(DAP4_DIN, PP5, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31ac),\
- PINGROUP(DAP4_DOUT, PP6, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31b0),\
- PINGROUP(DAP4_SCLK, PP7, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31b4),\
- PINGROUP(CLK3_OUT, PEE0, UART, EXTPERIPH3, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31b8),\
- PINGROUP(CLK3_REQ, PEE1, UART, DEV3, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31bc),\
- PINGROUP(GMI_WP_N, PC7, GMI, RSVD1, NAND, GMI, GMI_ALT, RSVD, INPUT, 0x31c0),\
- PINGROUP(GMI_IORDY, PI5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31c4),\
- PINGROUP(GMI_WAIT, PI7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31c8),\
- PINGROUP(GMI_ADV_N, PK0, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31cc),\
- PINGROUP(GMI_CLK, PK1, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31d0),\
- PINGROUP(GMI_CS0_N, PJ0, GMI, RSVD1, NAND, GMI, DTV, RSVD, INPUT, 0x31d4),\
- PINGROUP(GMI_CS1_N, PJ2, GMI, RSVD1, NAND, GMI, DTV, RSVD, INPUT, 0x31d8),\
- PINGROUP(GMI_CS2_N, PK3, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31dc),\
- PINGROUP(GMI_CS3_N, PK4, GMI, RSVD1, NAND, GMI, GMI_ALT, RSVD, INPUT, 0x31e0),\
- PINGROUP(GMI_CS4_N, PK2, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31e4),\
- PINGROUP(GMI_CS6_N, PI3, GMI, NAND, NAND_ALT, GMI, SATA, RSVD, INPUT, 0x31e8),\
- PINGROUP(GMI_CS7_N, PI6, GMI, NAND, NAND_ALT, GMI, GMI_ALT, RSVD, INPUT, 0x31ec),\
- PINGROUP(GMI_AD0, PG0, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f0),\
- PINGROUP(GMI_AD1, PG1, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f4),\
- PINGROUP(GMI_AD2, PG2, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f8),\
- PINGROUP(GMI_AD3, PG3, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31fc),\
- PINGROUP(GMI_AD4, PG4, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3200),\
- PINGROUP(GMI_AD5, PG5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3204),\
- PINGROUP(GMI_AD6, PG6, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3208),\
- PINGROUP(GMI_AD7, PG7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x320c),\
- PINGROUP(GMI_AD8, PH0, GMI, PWM0, NAND, GMI, RSVD2, RSVD, INPUT, 0x3210),\
- PINGROUP(GMI_AD9, PH1, GMI, PWM1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3214),\
- PINGROUP(GMI_AD10, PH2, GMI, PWM2, NAND, GMI, RSVD2, RSVD, INPUT, 0x3218),\
- PINGROUP(GMI_AD11, PH3, GMI, PWM3, NAND, GMI, RSVD2, RSVD, INPUT, 0x321c),\
- PINGROUP(GMI_AD12, PH4, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3220),\
- PINGROUP(GMI_AD13, PH5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3224),\
- PINGROUP(GMI_AD14, PH6, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3228),\
- PINGROUP(GMI_AD15, PH7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x322c),\
- PINGROUP(GMI_A16, PJ7, GMI, UARTD, SPI4, GMI, GMI_ALT, RSVD, INPUT, 0x3230),\
- PINGROUP(GMI_A17, PB0, GMI, UARTD, SPI4, GMI, DTV, RSVD, INPUT, 0x3234),\
- PINGROUP(GMI_A18, PB1, GMI, UARTD, SPI4, GMI, DTV, RSVD, INPUT, 0x3238),\
- PINGROUP(GMI_A19, PK7, GMI, UARTD, SPI4, GMI, RSVD3, RSVD, INPUT, 0x323c),\
- PINGROUP(GMI_WR_N, PI0, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3240),\
- PINGROUP(GMI_OE_N, PI1, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3244),\
- PINGROUP(GMI_DQS, PI2, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3248),\
- PINGROUP(GMI_RST_N, PI4, GMI, NAND, NAND_ALT, GMI, RSVD3, RSVD, INPUT, 0x324c),\
- PINGROUP(GEN2_I2C_SCL, PT5, GMI, I2C2, INVALID, GMI, RSVD3, RSVD, INPUT, 0x3250),\
- PINGROUP(GEN2_I2C_SDA, PT6, GMI, I2C2, INVALID, GMI, RSVD3, RSVD, INPUT, 0x3254),\
- PINGROUP(SDMMC4_CLK, PCC4, SDMMC4, INVALID, NAND, GMI, SDMMC4, RSVD, INPUT, 0x3258),\
- PINGROUP(SDMMC4_CMD, PT7, SDMMC4, I2C3, NAND, GMI, SDMMC4, RSVD, INPUT, 0x325c),\
- PINGROUP(SDMMC4_DAT0, PAA0, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x3260),\
- PINGROUP(SDMMC4_DAT1, PAA1, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x3264),\
- PINGROUP(SDMMC4_DAT2, PAA2, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x3268),\
- PINGROUP(SDMMC4_DAT3, PAA3, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x326c),\
- PINGROUP(SDMMC4_DAT4, PAA4, SDMMC4, I2C3, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x3270),\
- PINGROUP(SDMMC4_DAT5, PAA5, SDMMC4, VGP3, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x3274),\
- PINGROUP(SDMMC4_DAT6, PAA6, SDMMC4, VGP4, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x3278),\
- PINGROUP(SDMMC4_DAT7, PAA7, SDMMC4, VGP5, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x327c),\
+ PINGROUP(VI_VSYNC, PD6, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x315c),\
+ PINGROUP(VI_HSYNC, PD7, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x3160),\
+ PINGROUP(UART2_RXD, PC3, UART, IRDA, SPDIF, UARTA, SPI4, IRDA, INPUT, 0x3164),\
+ PINGROUP(UART2_TXD, PC2, UART, IRDA, SPDIF, UARTA, SPI4, IRDA, INPUT, 0x3168),\
+ PINGROUP(UART2_RTS_N, PJ6, UART, UARTA, UARTB, GMI, SPI4, UARTB, INPUT, 0x316c),\
+ PINGROUP(UART2_CTS_N, PJ5, UART, UARTA, UARTB, GMI, SPI4, UARTB, INPUT, 0x3170),\
+ PINGROUP(UART3_TXD, PW6, UART, UARTC, RSVD1, GMI, RSVD2, UARTC, INPUT, 0x3174),\
+ PINGROUP(UART3_RXD, PW7, UART, UARTC, RSVD1, GMI, RSVD2, UARTC, INPUT, 0x3178),\
+ PINGROUP(UART3_CTS_N, PA1, UART, UARTC, RSVD1, GMI, RSVD2, UARTC, INPUT, 0x317c),\
+ PINGROUP(UART3_RTS_N, PC0, UART, UARTC, PWM0, GMI, RSVD2, UARTC, INPUT, 0x3180),\
+ PINGROUP(GPIO_PU0, PU0, UART, OWR, UARTA, GMI, RSVD1, GMI, INPUT, 0x3184),\
+ PINGROUP(GPIO_PU1, PU1, UART, RSVD1, UARTA, GMI, RSVD2, GMI, INPUT, 0x3188),\
+ PINGROUP(GPIO_PU2, PU2, UART, RSVD1, UARTA, GMI, RSVD2, GMI, INPUT, 0x318c),\
+ PINGROUP(GPIO_PU3, PU3, UART, PWM0, UARTA, GMI, RSVD1, GMI, INPUT, 0x3190),\
+ PINGROUP(GPIO_PU4, PU4, UART, PWM1, UARTA, GMI, RSVD1, GMI, INPUT, 0x3194),\
+ PINGROUP(GPIO_PU5, PU5, UART, PWM2, UARTA, GMI, RSVD1, GMI, INPUT, 0x3198),\
+ PINGROUP(GPIO_PU6, PU6, UART, PWM3, UARTA, GMI, RSVD1, GMI, INPUT, 0x319c),\
+ PINGROUP(GEN1_I2C_SDA, PC5, UART, I2C1, RSVD1, RSVD2, RSVD3, I2C1, INPUT, 0x31a0),\
+ PINGROUP(GEN1_I2C_SCL, PC4, UART, I2C1, RSVD1, RSVD2, RSVD3, I2C1, INPUT, 0x31a4),\
+ PINGROUP(DAP4_FS, PP4, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31a8),\
+ PINGROUP(DAP4_DIN, PP5, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31ac),\
+ PINGROUP(DAP4_DOUT, PP6, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31b0),\
+ PINGROUP(DAP4_SCLK, PP7, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31b4),\
+ PINGROUP(CLK3_OUT, PEE0, UART, EXTPERIPH3, RSVD1, RSVD2, RSVD3, EXTPERIPH3, INPUT, 0x31b8),\
+ PINGROUP(CLK3_REQ, PEE1, UART, DEV3, RSVD1, RSVD2, RSVD3, DEV3, INPUT, 0x31bc),\
+ PINGROUP(GMI_WP_N, PC7, GMI, RSVD1, NAND, GMI, GMI_ALT, GMI, INPUT, 0x31c0),\
+ PINGROUP(GMI_IORDY, PI5, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31c4),\
+ PINGROUP(GMI_WAIT, PI7, GMI, RSVD1, NAND, GMI, RSVD2, NAND, INPUT, 0x31c8),\
+ PINGROUP(GMI_ADV_N, PK0, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31cc),\
+ PINGROUP(GMI_CLK, PK1, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31d0),\
+ PINGROUP(GMI_CS0_N, PJ0, GMI, RSVD1, NAND, GMI, DTV, GMI, INPUT, 0x31d4),\
+ PINGROUP(GMI_CS1_N, PJ2, GMI, RSVD1, NAND, GMI, DTV, GMI, INPUT, 0x31d8),\
+ PINGROUP(GMI_CS2_N, PK3, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31dc),\
+ PINGROUP(GMI_CS3_N, PK4, GMI, RSVD1, NAND, GMI, GMI_ALT, GMI, INPUT, 0x31e0),\
+ PINGROUP(GMI_CS4_N, PK2, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31e4),\
+ PINGROUP(GMI_CS6_N, PI3, GMI, NAND, NAND_ALT, GMI, SATA, NAND, INPUT, 0x31e8),\
+ PINGROUP(GMI_CS7_N, PI6, GMI, NAND, NAND_ALT, GMI, GMI_ALT, NAND, INPUT, 0x31ec),\
+ PINGROUP(GMI_AD0, PG0, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31f0),\
+ PINGROUP(GMI_AD1, PG1, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31f4),\
+ PINGROUP(GMI_AD2, PG2, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31f8),\
+ PINGROUP(GMI_AD3, PG3, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31fc),\
+ PINGROUP(GMI_AD4, PG4, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3200),\
+ PINGROUP(GMI_AD5, PG5, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3204),\
+ PINGROUP(GMI_AD6, PG6, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3208),\
+ PINGROUP(GMI_AD7, PG7, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x320c),\
+ PINGROUP(GMI_AD8, PH0, GMI, PWM0, NAND, GMI, RSVD2, GMI, INPUT, 0x3210),\
+ PINGROUP(GMI_AD9, PH1, GMI, PWM1, NAND, GMI, RSVD2, GMI, INPUT, 0x3214),\
+ PINGROUP(GMI_AD10, PH2, GMI, PWM2, NAND, GMI, RSVD2, GMI, INPUT, 0x3218),\
+ PINGROUP(GMI_AD11, PH3, GMI, PWM3, NAND, GMI, RSVD2, GMI, INPUT, 0x321c),\
+ PINGROUP(GMI_AD12, PH4, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3220),\
+ PINGROUP(GMI_AD13, PH5, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3224),\
+ PINGROUP(GMI_AD14, PH6, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3228),\
+ PINGROUP(GMI_AD15, PH7, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x322c),\
+ PINGROUP(GMI_A16, PJ7, GMI, UARTD, SPI4, GMI, GMI_ALT, GMI, INPUT, 0x3230),\
+ PINGROUP(GMI_A17, PB0, GMI, UARTD, SPI4, GMI, DTV, GMI, INPUT, 0x3234),\
+ PINGROUP(GMI_A18, PB1, GMI, UARTD, SPI4, GMI, DTV, GMI, INPUT, 0x3238),\
+ PINGROUP(GMI_A19, PK7, GMI, UARTD, SPI4, GMI, RSVD3, GMI, INPUT, 0x323c),\
+ PINGROUP(GMI_WR_N, PI0, GMI, RSVD1, NAND, GMI, RSVD3, GMI, INPUT, 0x3240),\
+ PINGROUP(GMI_OE_N, PI1, GMI, RSVD1, NAND, GMI, RSVD3, GMI, INPUT, 0x3244),\
+ PINGROUP(GMI_DQS, PI2, GMI, RSVD1, NAND, GMI, RSVD3, NAND, INPUT, 0x3248),\
+ PINGROUP(GMI_RST_N, PI4, GMI, NAND, NAND_ALT, GMI, RSVD3, NAND, INPUT, 0x324c),\
+ PINGROUP(GEN2_I2C_SCL, PT5, GMI, I2C2, INVALID, GMI, RSVD3, I2C2, INPUT, 0x3250),\
+ PINGROUP(GEN2_I2C_SDA, PT6, GMI, I2C2, INVALID, GMI, RSVD3, I2C2, INPUT, 0x3254),\
+ PINGROUP(SDMMC4_CLK, PCC4, SDMMC4, INVALID, NAND, GMI, SDMMC4, GMI, INPUT, 0x3258),\
+ PINGROUP(SDMMC4_CMD, PT7, SDMMC4, I2C3, NAND, GMI, SDMMC4, GMI, INPUT, 0x325c),\
+ PINGROUP(SDMMC4_DAT0, PAA0, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x3260),\
+ PINGROUP(SDMMC4_DAT1, PAA1, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x3264),\
+ PINGROUP(SDMMC4_DAT2, PAA2, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x3268),\
+ PINGROUP(SDMMC4_DAT3, PAA3, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x326c),\
+ PINGROUP(SDMMC4_DAT4, PAA4, SDMMC4, I2C3, I2S4, GMI, SDMMC4, GMI, INPUT, 0x3270),\
+ PINGROUP(SDMMC4_DAT5, PAA5, SDMMC4, VGP3, I2S4, GMI, SDMMC4, GMI, INPUT, 0x3274),\
+ PINGROUP(SDMMC4_DAT6, PAA6, SDMMC4, VGP4, I2S4, GMI, SDMMC4, GMI, INPUT, 0x3278),\
+ PINGROUP(SDMMC4_DAT7, PAA7, SDMMC4, VGP5, I2S4, GMI, SDMMC4, GMI, INPUT, 0x327c),\
PINGROUP(SDMMC4_RST_N, PCC3, SDMMC4, VGP6, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3280),\
PINGROUP(CAM_MCLK, PCC0, CAM, VI, INVALID, VI_ALT2, POPSDMMC4, RSVD, INPUT, 0x3284),\
PINGROUP(GPIO_PCC1, PCC1, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3288),\
@@ -312,82 +312,82 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
PINGROUP(GPIO_PBB6, PBB6, CAM, VGP6, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x32a4),\
PINGROUP(GPIO_PBB7, PBB7, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x32a8),\
PINGROUP(GPIO_PCC2, PCC2, CAM, I2S4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32ac),\
- PINGROUP(JTAG_RTCK, PU7, SYS, RTCK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b0),\
- PINGROUP(PWR_I2C_SCL, PZ6, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b4),\
- PINGROUP(PWR_I2C_SDA, PZ7, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b8),\
- PINGROUP(KB_ROW0, PR0, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32bc),\
- PINGROUP(KB_ROW1, PR1, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32c0),\
- PINGROUP(KB_ROW2, PR2, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32c4),\
- PINGROUP(KB_ROW3, PR3, SYS, KBC, INVALID, RSVD2, INVALID, RSVD, INPUT, 0x32c8),\
- PINGROUP(KB_ROW4, PR4, SYS, KBC, INVALID, TRACE, RSVD3, RSVD, INPUT, 0x32cc),\
- PINGROUP(KB_ROW5, PR5, SYS, KBC, INVALID, TRACE, OWR, RSVD, INPUT, 0x32d0),\
- PINGROUP(KB_ROW6, PR6, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32d4),\
- PINGROUP(KB_ROW7, PR7, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32d8),\
- PINGROUP(KB_ROW8, PS0, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32dc),\
- PINGROUP(KB_ROW9, PS1, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32e0),\
- PINGROUP(KB_ROW10, PS2, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32e4),\
- PINGROUP(KB_ROW11, PS3, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32e8),\
- PINGROUP(KB_ROW12, PS4, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32ec),\
- PINGROUP(KB_ROW13, PS5, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32f0),\
- PINGROUP(KB_ROW14, PS6, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32f4),\
- PINGROUP(KB_ROW15, PS7, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32f8),\
- PINGROUP(KB_COL0, PQ0, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x32fc),\
- PINGROUP(KB_COL1, PQ1, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3300),\
- PINGROUP(KB_COL2, PQ2, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3304),\
- PINGROUP(KB_COL3, PQ3, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3308),\
- PINGROUP(KB_COL4, PQ4, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x330c),\
- PINGROUP(KB_COL5, PQ5, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3310),\
- PINGROUP(KB_COL6, PQ6, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3314),\
- PINGROUP(KB_COL7, PQ7, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3318),\
- PINGROUP(CLK_32K_OUT, PA0, SYS, BLINK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x331c),\
- PINGROUP(SYS_CLK_REQ, PZ5, SYS, SYSCLK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3320),\
+ PINGROUP(JTAG_RTCK, PU7, SYS, RTCK, RSVD1, RSVD2, RSVD3, RTCK, INPUT, 0x32b0),\
+ PINGROUP(PWR_I2C_SCL, PZ6, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, I2CPWR, INPUT, 0x32b4),\
+ PINGROUP(PWR_I2C_SDA, PZ7, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, I2CPWR, INPUT, 0x32b8),\
+ PINGROUP(KB_ROW0, PR0, SYS, KBC, INVALID, RSVD2, RSVD3, KBC, INPUT, 0x32bc),\
+ PINGROUP(KB_ROW1, PR1, SYS, KBC, INVALID, RSVD2, RSVD3, KBC, INPUT, 0x32c0),\
+ PINGROUP(KB_ROW2, PR2, SYS, KBC, INVALID, RSVD2, RSVD3, KBC, INPUT, 0x32c4),\
+ PINGROUP(KB_ROW3, PR3, SYS, KBC, INVALID, RSVD2, INVALID, KBC, INPUT, 0x32c8),\
+ PINGROUP(KB_ROW4, PR4, SYS, KBC, INVALID, TRACE, RSVD3, KBC, INPUT, 0x32cc),\
+ PINGROUP(KB_ROW5, PR5, SYS, KBC, INVALID, TRACE, OWR, KBC, INPUT, 0x32d0),\
+ PINGROUP(KB_ROW6, PR6, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32d4),\
+ PINGROUP(KB_ROW7, PR7, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32d8),\
+ PINGROUP(KB_ROW8, PS0, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32dc),\
+ PINGROUP(KB_ROW9, PS1, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32e0),\
+ PINGROUP(KB_ROW10, PS2, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32e4),\
+ PINGROUP(KB_ROW11, PS3, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32e8),\
+ PINGROUP(KB_ROW12, PS4, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32ec),\
+ PINGROUP(KB_ROW13, PS5, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32f0),\
+ PINGROUP(KB_ROW14, PS6, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32f4),\
+ PINGROUP(KB_ROW15, PS7, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32f8),\
+ PINGROUP(KB_COL0, PQ0, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x32fc),\
+ PINGROUP(KB_COL1, PQ1, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x3300),\
+ PINGROUP(KB_COL2, PQ2, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x3304),\
+ PINGROUP(KB_COL3, PQ3, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x3308),\
+ PINGROUP(KB_COL4, PQ4, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x330c),\
+ PINGROUP(KB_COL5, PQ5, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x3310),\
+ PINGROUP(KB_COL6, PQ6, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x3314),\
+ PINGROUP(KB_COL7, PQ7, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x3318),\
+ PINGROUP(CLK_32K_OUT, PA0, SYS, BLINK, RSVD1, RSVD2, RSVD3, BLINK, INPUT, 0x331c),\
+ PINGROUP(SYS_CLK_REQ, PZ5, SYS, SYSCLK, RSVD1, RSVD2, RSVD3, SYSCLK, INPUT, 0x3320),\
PINGROUP(CORE_PWR_REQ, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3324),\
PINGROUP(CPU_PWR_REQ, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3328),\
PINGROUP(PWR_INT_N, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x332c),\
PINGROUP(CLK_32K_IN, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3330),\
- PINGROUP(OWR, INVALID, SYS, OWR, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3334),\
- PINGROUP(DAP1_FS, PN0, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x3338),\
- PINGROUP(DAP1_DIN, PN1, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x333c),\
- PINGROUP(DAP1_DOUT, PN2, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x3340),\
- PINGROUP(DAP1_SCLK, PN3, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x3344),\
- PINGROUP(CLK1_REQ, PEE2, AUDIO, DAP, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x3348),\
- PINGROUP(CLK1_OUT, PW4, AUDIO, EXTPERIPH1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x334c),\
+ PINGROUP(OWR, INVALID, SYS, OWR, RSVD, RSVD, RSVD, OWR, INPUT, 0x3334),\
+ PINGROUP(DAP1_FS, PN0, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x3338),\
+ PINGROUP(DAP1_DIN, PN1, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x333c),\
+ PINGROUP(DAP1_DOUT, PN2, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x3340),\
+ PINGROUP(DAP1_SCLK, PN3, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x3344),\
+ PINGROUP(CLK1_REQ, PEE2, AUDIO, DAP, HDA, RSVD2, RSVD3, DAP, INPUT, 0x3348),\
+ PINGROUP(CLK1_OUT, PW4, AUDIO, EXTPERIPH1, RSVD1, RSVD2, RSVD3, EXTPERIPH1, INPUT, 0x334c),\
PINGROUP(SPDIF_IN, PK6, AUDIO, SPDIF, HDA, INVALID, DAPSDMMC2, RSVD, INPUT, 0x3350),\
PINGROUP(SPDIF_OUT, PK5, AUDIO, SPDIF, RSVD1, INVALID, DAPSDMMC2, RSVD, INPUT, 0x3354),\
- PINGROUP(DAP2_FS, PA2, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3358),\
- PINGROUP(DAP2_DIN, PA4, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x335c),\
- PINGROUP(DAP2_DOUT, PA5, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3360),\
- PINGROUP(DAP2_SCLK, PA3, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3364),\
- PINGROUP(SPI2_MOSI, PX0, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3368),\
- PINGROUP(SPI2_MISO, PX1, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x336c),\
- PINGROUP(SPI2_CS0_N, PX3, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3370),\
- PINGROUP(SPI2_SCK, PX2, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3374),\
- PINGROUP(SPI1_MOSI, PX4, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x3378),\
- PINGROUP(SPI1_SCK, PX5, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x337c),\
- PINGROUP(SPI1_CS0_N, PX6, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x3380),\
+ PINGROUP(DAP2_FS, PA2, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x3358),\
+ PINGROUP(DAP2_DIN, PA4, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x335c),\
+ PINGROUP(DAP2_DOUT, PA5, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x3360),\
+ PINGROUP(DAP2_SCLK, PA3, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x3364),\
+ PINGROUP(SPI2_MOSI, PX0, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x3368),\
+ PINGROUP(SPI2_MISO, PX1, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x336c),\
+ PINGROUP(SPI2_CS0_N, PX3, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x3370),\
+ PINGROUP(SPI2_SCK, PX2, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x3374),\
+ PINGROUP(SPI1_MOSI, PX4, AUDIO, SPI2, SPI1, INVALID, GMI, GMI, INPUT, 0x3378),\
+ PINGROUP(SPI1_SCK, PX5, AUDIO, SPI2, SPI1, INVALID, GMI, GMI, INPUT, 0x337c),\
+ PINGROUP(SPI1_CS0_N, PX6, AUDIO, SPI2, SPI1, INVALID, GMI, GMI, INPUT, 0x3380),\
PINGROUP(SPI1_MISO, PX7, AUDIO, INVALID, SPI1, INVALID, RSVD3, RSVD, INPUT, 0x3384),\
PINGROUP(SPI2_CS1_N, PW2, AUDIO, INVALID, SPI2, INVALID, INVALID, RSVD, INPUT, 0x3388),\
PINGROUP(SPI2_CS2_N, PW3, AUDIO, INVALID, SPI2, INVALID, INVALID, RSVD, INPUT, 0x338c),\
- PINGROUP(SDMMC3_CLK, PA6, SDMMC3, UARTA, PWM2, SDMMC3, INVALID, RSVD, INPUT, 0x3390),\
- PINGROUP(SDMMC3_CMD, PA7, SDMMC3, UARTA, PWM3, SDMMC3, INVALID, RSVD, INPUT, 0x3394),\
- PINGROUP(SDMMC3_DAT0, PB7, SDMMC3, RSVD0, RSVD1, SDMMC3, INVALID, RSVD, INPUT, 0x3398),\
- PINGROUP(SDMMC3_DAT1, PB6, SDMMC3, RSVD0, RSVD1, SDMMC3, INVALID, RSVD, INPUT, 0x339c),\
- PINGROUP(SDMMC3_DAT2, PB5, SDMMC3, RSVD0, PWM1, SDMMC3, INVALID, RSVD, INPUT, 0x33a0),\
- PINGROUP(SDMMC3_DAT3, PB4, SDMMC3, RSVD0, PWM0, SDMMC3, INVALID, RSVD, INPUT, 0x33a4),\
- PINGROUP(SDMMC3_DAT4, PD1, SDMMC3, PWM1, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33a8),\
- PINGROUP(SDMMC3_DAT5, PD0, SDMMC3, PWM0, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33ac),\
- PINGROUP(SDMMC3_DAT6, PD3, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33b0),\
- PINGROUP(SDMMC3_DAT7, PD4, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33b4),\
- PINGROUP(PEX_L0_PRSNT_N, PDD0, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33b8),\
- PINGROUP(PEX_L0_RST_N, PDD1, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33bc),\
- PINGROUP(PEX_L0_CLKREQ_N, PDD2, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c0),\
- PINGROUP(PEX_WAKE_N, PDD3, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c4),\
- PINGROUP(PEX_L1_PRSNT_N, PDD4, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c8),\
- PINGROUP(PEX_L1_RST_N, PDD5, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33cc),\
- PINGROUP(PEX_L1_CLKREQ_N, PDD6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d0),\
- PINGROUP(PEX_L2_PRSNT_N, PDD7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d4),\
- PINGROUP(PEX_L2_RST_N, PCC6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d8),\
- PINGROUP(PEX_L2_CLKREQ_N, PCC7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33dc),\
+ PINGROUP(SDMMC3_CLK, PA6, SDMMC3, UARTA, PWM2, SDMMC3, INVALID, SDMMC3, INPUT, 0x3390),\
+ PINGROUP(SDMMC3_CMD, PA7, SDMMC3, UARTA, PWM3, SDMMC3, INVALID, SDMMC3, INPUT, 0x3394),\
+ PINGROUP(SDMMC3_DAT0, PB7, SDMMC3, RSVD0, RSVD1, SDMMC3, INVALID, SDMMC3, INPUT, 0x3398),\
+ PINGROUP(SDMMC3_DAT1, PB6, SDMMC3, RSVD0, RSVD1, SDMMC3, INVALID, SDMMC3, INPUT, 0x339c),\
+ PINGROUP(SDMMC3_DAT2, PB5, SDMMC3, RSVD0, PWM1, SDMMC3, INVALID, SDMMC3, INPUT, 0x33a0),\
+ PINGROUP(SDMMC3_DAT3, PB4, SDMMC3, RSVD0, PWM0, SDMMC3, INVALID, SDMMC3, INPUT, 0x33a4),\
+ PINGROUP(SDMMC3_DAT4, PD1, SDMMC3, PWM1, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33a8),\
+ PINGROUP(SDMMC3_DAT5, PD0, SDMMC3, PWM0, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33ac),\
+ PINGROUP(SDMMC3_DAT6, PD3, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33b0),\
+ PINGROUP(SDMMC3_DAT7, PD4, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33b4),\
+ PINGROUP(PEX_L0_PRSNT_N, PDD0, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33b8),\
+ PINGROUP(PEX_L0_RST_N, PDD1, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33bc),\
+ PINGROUP(PEX_L0_CLKREQ_N, PDD2, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33c0),\
+ PINGROUP(PEX_WAKE_N, PDD3, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33c4),\
+ PINGROUP(PEX_L1_PRSNT_N, PDD4, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33c8),\
+ PINGROUP(PEX_L1_RST_N, PDD5, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33cc),\
+ PINGROUP(PEX_L1_CLKREQ_N, PDD6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33d0),\
+ PINGROUP(PEX_L2_PRSNT_N, PDD7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33d4),\
+ PINGROUP(PEX_L2_RST_N, PCC6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33d8),\
+ PINGROUP(PEX_L2_CLKREQ_N, PCC7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33dc),\
PINGROUP(HDMI_CEC, PEE3, SYS, CEC, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x33e0),\
/* END OF LIST */
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index ed6c01fe8544..d1178a820f39 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -290,7 +290,10 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
#if defined(CONFIG_HAVE_ARM_SCU)
{
- u32 scu_ctrl = __raw_readl(scu_base) | 1 << 3;
+ u32 scu_ctrl = __raw_readl(scu_base) |
+ 1 << 3 | /* Enable speculative line fill*/
+ 1 << 5 | /* Enable IC standby */
+ 1 << 6; /* Enable SCU standby */
if (!(scu_ctrl & 1))
__raw_writel(scu_ctrl, scu_base);
}
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index e53effb9b669..054eb3aea358 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -54,7 +54,6 @@
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
-#include <asm/suspend.h>
#include <mach/clk.h>
#include <mach/iomap.h>
@@ -98,6 +97,9 @@ struct suspend_context {
};
#ifdef CONFIG_PM_SLEEP
+#if USE_TEGRA_CPU_SUSPEND
+void *tegra_cpu_context; /* non-cacheable page for CPU context */
+#endif
phys_addr_t tegra_pgd_phys; /* pgd used by hotplug & LP2 bootup */
static pgd_t *tegra_pgd;
static DEFINE_SPINLOCK(tegra_lp2_lock);
@@ -264,6 +266,63 @@ static __init int create_suspend_pgtable(void)
return 0;
}
+/*
+ * alloc_suspend_context
+ *
+ * Allocate a non-cacheable page to hold the CPU contexts.
+ * The standard ARM CPU context save functions don't work if there's
+ * an external L2 cache controller (like a PL310) in system.
+ */
+static __init int alloc_suspend_context(void)
+{
+#if USE_TEGRA_CPU_SUSPEND
+ pgprot_t prot = __pgprot_modify(pgprot_kernel, L_PTE_MT_MASK,
+ L_PTE_MT_BUFFERABLE | L_PTE_XN);
+ struct page *ctx_page;
+ unsigned long ctx_virt = 0;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ ctx_page = alloc_pages(GFP_KERNEL, 0);
+ if (IS_ERR_OR_NULL(ctx_page))
+ goto fail;
+
+ tegra_cpu_context = vm_map_ram(&ctx_page, 1, -1, prot);
+ if (IS_ERR_OR_NULL(tegra_cpu_context))
+ goto fail;
+
+ /* Add the context page to our private pgd. */
+ ctx_virt = (unsigned long)tegra_cpu_context;
+
+ pgd = tegra_pgd + pgd_index(ctx_virt);
+ if (!pgd_present(*pgd))
+ goto fail;
+ pmd = pmd_offset(pgd, ctx_virt);
+ if (!pmd_none(*pmd))
+ goto fail;
+ pte = pte_alloc_kernel(pmd, ctx_virt);
+ if (!pte)
+ goto fail;
+
+ set_pte_ext(pte, mk_pte(ctx_page, prot), 0);
+
+ outer_clean_range(__pa(pmd), __pa(pmd + 1));
+
+ return 0;
+
+fail:
+ if (ctx_page)
+ __free_page(ctx_page);
+ if (ctx_virt)
+ vm_unmap_ram((void*)ctx_virt, 1);
+ tegra_cpu_context = NULL;
+ return -ENOMEM;
+#else
+ return 0;
+#endif
+}
+
/* ensures that sufficient time is passed for a register write to
* serialize into the 32KHz domain */
static void pmc_32kwritel(u32 val, unsigned long offs)
@@ -496,9 +555,9 @@ static void tegra_sleep_core(enum tegra_suspend_mode mode,
}
#endif
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- cpu_suspend(v2p, tegra2_sleep_core_finish);
+ tegra2_sleep_core(v2p);
#else
- cpu_suspend(v2p, tegra3_sleep_core_finish);
+ tegra3_sleep_core(v2p);
#endif
}
@@ -509,7 +568,7 @@ static inline void tegra_sleep_cpu(unsigned long v2p)
(TEGRA_RESET_HANDLER_BASE +
tegra_cpu_reset_handler_offset));
#endif
- cpu_suspend(v2p, tegra_sleep_cpu_finish);
+ tegra_sleep_cpu_save(v2p);
}
unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
@@ -526,8 +585,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
else
mode |= TEGRA_POWER_PWRREQ_OE;
mode &= ~TEGRA_POWER_EFFECT_LP0;
- pmc_32kwritel(mode, PMC_CTRL);
- mode |= flags;
+ writel(mode, pmc + PMC_CTRL);
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_start);
@@ -539,7 +597,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
trace_cpu_cluster(POWER_CPU_CLUSTER_START);
set_power_timers(pdata->cpu_timer, 0,
clk_get_rate_all_locked(tegra_pclk));
- tegra_cluster_switch_prolog(mode);
+ tegra_cluster_switch_prolog(flags);
} else {
set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer,
clk_get_rate_all_locked(tegra_pclk));
@@ -549,7 +607,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
tegra_lp2_set_trigger(sleep_time);
cpu_complex_pm_enter();
- suspend_cpu_complex(mode);
+ suspend_cpu_complex(flags);
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_prolog);
flush_cache_all();
/*
@@ -566,7 +624,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
tegra_init_cache(false);
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_switch);
- restore_cpu_complex(mode);
+ restore_cpu_complex(flags);
cpu_complex_pm_exit();
remain = tegra_lp2_timer_remain();
@@ -574,7 +632,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
tegra_lp2_set_trigger(0);
if (flags & TEGRA_POWER_CLUSTER_MASK) {
- tegra_cluster_switch_epilog(mode);
+ tegra_cluster_switch_epilog(flags);
trace_cpu_cluster(POWER_CPU_CLUSTER_DONE);
}
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_epilog);
@@ -819,6 +877,8 @@ int tegra_suspend_dram(enum tegra_suspend_mode mode, unsigned int flags)
local_fiq_disable();
+ trace_cpu_suspend(CPU_SUSPEND_START);
+
cpu_pm_enter();
cpu_complex_pm_enter();
@@ -882,6 +942,8 @@ int tegra_suspend_dram(enum tegra_suspend_mode mode, unsigned int flags)
if (pdata && pdata->board_resume)
pdata->board_resume(mode, TEGRA_RESUME_AFTER_CPU);
+ trace_cpu_suspend(CPU_SUSPEND_DONE);
+
local_fiq_enable();
tegra_common_resume();
@@ -1036,6 +1098,13 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
goto fail;
}
+ if (alloc_suspend_context() < 0) {
+ pr_err("%s: CPU context alloc failed -- LP0/LP1/LP2 unavailable\n",
+ __func__);
+ plat->suspend_mode = TEGRA_SUSPEND_NONE;
+ goto fail;
+ }
+
if ((tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) &&
(tegra_get_revision() == TEGRA_REVISION_A01) &&
(plat->suspend_mode == TEGRA_SUSPEND_LP0)) {
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 76d264fcad0e..4c0d8bec276e 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -19,6 +19,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -27,6 +28,7 @@
#include <linux/io.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
+#include <trace/events/power.h>
#include <mach/clk.h>
#include <mach/iomap.h>
@@ -460,6 +462,9 @@ static int tegra_powergate_set(int id, bool new_state)
return -EBUSY;
}
+ trace_power_domain_target(powergate_partition_info[id].name, new_state,
+ smp_processor_id());
+
return 0;
}
@@ -489,6 +494,7 @@ bool tegra_powergate_is_powered(int id)
status = pmc_read(PWRGATE_STATUS) & (1 << id);
return !!status;
}
+EXPORT_SYMBOL(tegra_powergate_is_powered);
int tegra_powergate_remove_clamping(int id)
{
diff --git a/arch/arm/mach-tegra/sleep-t2.S b/arch/arm/mach-tegra/sleep-t2.S
index b2055655ba93..f70360628f34 100644
--- a/arch/arm/mach-tegra/sleep-t2.S
+++ b/arch/arm/mach-tegra/sleep-t2.S
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/sleep-t2.S
*
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
* Copyright (c) 2011, Google, Inc.
*
* Author: Colin Cross <ccross@android.com>
@@ -179,39 +179,25 @@ ENDPROC(tegra2_cpu_is_resettable_soon)
* enters suspend in LP0 or LP1 by turning off the mmu and jumping to
* tegra2_tear_down_core in IRAM
*/
-ENTRY(tegra2_sleep_core_finish)
- bl tegra_cpu_exit_coherency
+ENTRY(tegra2_sleep_core)
+ mov r12, pc @ return here is via r12
+ b tegra_cpu_save
mov32 r1, tegra2_tear_down_core
mov32 r2, tegra2_iram_start
sub r1, r1, r2
mov32 r2, TEGRA_IRAM_CODE_AREA
add r1, r1, r2
b tegra_turn_off_mmu
-ENDPROC(tegra2_sleep_core_finish)
+ENDPROC(tegra2_sleep_core)
/*
* tegra2_sleep_wfi(unsigned long v2p)
*/
ENTRY(tegra2_sleep_wfi)
- stmfd sp!, {r4 - r9, lr}
- mov r9, sp @ save sp for aborted suspend
- adr r1, BSYM(tegra_sleep_cpu_save_finish)
- bl cpu_suspend
- ldmfd sp!, {r4 - r9, pc}
-
-tegra_sleep_cpu_save_finish:
- mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency
-
- dsb
-#ifdef MULTI_CACHE
- mov32 r10, cpu_cache
- mov lr, pc
- ldr pc, [r10, #CACHE_FLUSH_KERN_ALL]
-#else
- bl __cpuc_flush_kern_all
-#endif
-
- bl tegra_cpu_exit_coherency
+ mrc p15, 0, r2, c1, c0, 1 @ save actlr before exiting coherency
+ mov r12, pc @ return here is via r12
+ b tegra_cpu_save
+ mov r11, r2
mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
mov r3, #CPU_RESETTABLE
@@ -233,7 +219,7 @@ tegra_sleep_cpu_save_finish:
* r11 contains the original actlr
*/
- mov sp, r9 @ restore SP for aborted suspend
+ mov sp, r7 @ restore SP for aborted suspend
bl tegra_pen_lock
mov32 r3, TEGRA_PMC_VIRT
@@ -243,8 +229,18 @@ tegra_sleep_cpu_save_finish:
bl tegra_pen_unlock
+#if USE_TEGRA_CPU_SUSPEND
+ /* Enable the data cache and SMP coherency */
+ mrc p15, 0, r10, c1, c0, 0
+ orr r10, r10, #CR_C
+ dsb
+ mcr p15, 0, r10, c1, c0, 0
+ isb
mcr p15, 0, r11, c1, c0, 1 @ reenable coherency
+#else
+ mcr p15, 0, r11, c1, c0, 1 @ reenable coherency
+#endif
/* Invalidate the TLBs & BTAC */
mov r1, #0
mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
@@ -276,7 +272,8 @@ tegra_sleep_cpu_save_finish:
no_l2_sync:
#endif
- ldmfd sp!, {r4 - r9, pc}
+ pop_ctx_regs r0, r1 @ restore context registers
+ mov pc, lr
ENDPROC(tegra2_sleep_wfi)
/*
diff --git a/arch/arm/mach-tegra/sleep-t3.S b/arch/arm/mach-tegra/sleep-t3.S
index caabeb751390..4417da33de38 100644
--- a/arch/arm/mach-tegra/sleep-t3.S
+++ b/arch/arm/mach-tegra/sleep-t3.S
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/sleep-t3.S
*
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -201,13 +201,14 @@ ENDPROC(tegra3_cpu_reset)
#ifdef CONFIG_PM_SLEEP
/*
- * tegra3_sleep_core_finish(unsigned long int)
+ * tegra3_sleep_core(unsigned long v2p)
*
* enters suspend in LP0 or LP1 by turning off the mmu and jumping to
* tegra3_tear_down_core in IRAM
*/
-ENTRY(tegra3_sleep_core_finish)
- bl tegra_cpu_exit_coherency
+ENTRY(tegra3_sleep_core)
+ mov r12, pc @ return here is via r12
+ b tegra_cpu_save
/* preload all the address literals that are needed for the
* CPU power-gating process, to avoid loads from SDRAM (which are
@@ -226,33 +227,22 @@ ENTRY(tegra3_sleep_core_finish)
mov32 r2, TEGRA_IRAM_CODE_AREA
add r1, r1, r2
b tegra_turn_off_mmu
-ENDPROC(tegra3_sleep_core_finish)
+ENDPROC(tegra3_sleep_core)
/*
- * tegra3_sleep_cpu_secondary_finish(unsigned long v2p)
+ * tegra3_sleep_cpu_secondary(unsigned long v2p)
*
* Enters LP2 on secondary CPU by exiting coherency and powergating the CPU.
*/
-ENTRY(tegra3_sleep_cpu_secondary_finish)
- mov r6, lr
-
- dsb
-#ifdef MULTI_CACHE
- mov32 r10, cpu_cache
- mov lr, pc
- ldr pc, [r10, #CACHE_FLUSH_KERN_ALL]
-#else
- bl __cpuc_flush_kern_all
-#endif
-
- bl tegra_cpu_exit_coherency
+ENTRY(tegra3_sleep_cpu_secondary)
+ mov r12, pc @ return here is via r12
+ b tegra_cpu_save
/* Powergate this CPU. */
mov r0, #0 @ power mode flags (!hotplug)
bl tegra3_cpu_reset
- mov r0, #1 @ never return here
- mov pc, r6
-ENDPROC(tegra3_sleep_cpu_secondary_finish)
+ b . @ should never get here
+ENDPROC(tegra3_sleep_cpu_secondary)
/*
* tegra3_tear_down_cpu
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index 18b8799ea328..973c8677bafe 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -131,13 +131,225 @@ ENDPROC(tegra_cpu_exit_coherency)
#ifdef CONFIG_PM_SLEEP
/*
- * tegra_sleep_cpu_finish(unsigned long int)
+ * Restore CPU state for a suspend
+ *
+ * NOTE: This is a copy of cpu_resume in arch/arm/sleep.S that has been
+ * modified to work with an L2 cache.
+ */
+ .align L1_CACHE_SHIFT
+ENTRY(tegra_cpu_resume_phys)
+#if USE_TEGRA_CPU_SUSPEND
+#ifdef CONFIG_SMP
+ adr r0, tegra_phys_sleep_sp
+ ALT_SMP(mrc p15, 0, r1, c0, c0, 5)
+ ALT_UP(mov r1, #0)
+ and r1, r1, #15
+ ldr r0, [r0, r1, lsl #2] @ stack phys addr
+#else
+ ldr r0, tegra_phys_sleep_sp @ stack phys addr
+#endif
+ setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off
+ @ load v:p, stack, resume fn
+ ARM( ldmia r0!, {r1, sp, pc} )
+THUMB( ldmia r0!, {r1, r2, r3} )
+THUMB( mov sp, r2 )
+THUMB( bx r3 )
+#else
+ /* Use the standard cpu_resume. */
+ b cpu_resume
+#endif
+ENDPROC(tegra_cpu_resume_phys)
+
+#if USE_TEGRA_CPU_SUSPEND
+tegra_phys_sleep_sp:
+ .rept 4
+ .long 0 @ preserve stack phys ptr here
+ .endr
+#endif
+
+/*
+ * tegra_cpu_suspend
+ *
+ * Save CPU suspend state
+ * NOTE: This is a copy of cpu_suspend in arch/arm/sleep.S that has been
+ * modified to work with an L2 cache.
+ *
+ * Input:
+ * r1 = v:p offset
+ * lr = return to the caller of this function
+ * Output:
+ * sp is decremented to allocate space for CPU state on stack
+ * r0-r3,r8,r9,ip,lr corrupted
+ */
+ .align L1_CACHE_SHIFT
+ENTRY(tegra_cpu_suspend)
+ mov r9, lr
+ adr lr, tegra_cpu_resume
+#if USE_TEGRA_CPU_SUSPEND
+ stmfd sp!, {r4 - r11, lr}
+#ifdef MULTI_CPU
+ mov32 r10, processor
+ ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
+ ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function
+#else
+ mov32 r5, cpu_suspend_size
+ mov32 ip, cpu_do_resume
+#endif
+ mov r6, sp @ current virtual SP
+ sub sp, sp, r5 @ allocate CPU state on stack
+ mov r0, sp @ save pointer to CPU save block
+ add ip, ip, r1 @ convert resume fn to phys
+ stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn
+
+#ifdef MULTI_CPU
+ mov lr, pc
+ ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state
+#else
+ bl cpu_do_suspend
+#endif
+ dsb
+
+ /* Disable the data cache */
+ mrc p15, 0, r10, c1, c0, 0
+ bic r10, r10, #CR_C
+ dsb
+ mcr p15, 0, r10, c1, c0, 0
+ isb
+
+ /* Flush data cache */
+#ifdef MULTI_CACHE
+ mov32 r10, cpu_cache
+ mov lr, pc
+ ldr pc, [r10, #CACHE_FLUSH_KERN_ALL]
+#else
+ bl __cpuc_flush_kern_all
+#endif
+#ifdef CONFIG_CACHE_L2X0
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ cpu_id r2
+ cmp r2, #0
+ bne no_l2_sync
+#endif
+ /* Issue a PL310 cache sync operation */
+ dsb
+ mov32 r2, TEGRA_PL310_VIRT
+ movw r1, 0x730 @ cache sync
+ add r2, r2, r1
+ mov r1, #0
+ str r1, [r2]
+#endif
+
+no_l2_sync:
+ /* Invalidate the TLBs & BTAC */
+ mov r1, #0
+ mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
+ mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC
+ dsb
+ isb
+
+ /* Turn off SMP coherency */
+ exit_smp r1, r2
+
+ /* Convert SP from virtual to physical address. */
+ movw r1, #0xFFF
+ bic r2, sp, r1 @ VA & 0xFFFFF000
+ mcr p15, 0, r2, c7, c8, 0 @ V2PPRPC
+ mrc p15, 0, r2, c7, c4, 0 @ PAR
+ bic r2, r2, r1 @ PA & 0xFFFFF000
+ and r0, sp, r1 @ VA & 0x00000FFF
+ orr r2, r0, r2 @ (PA & 0xFFFFF000) | (VA & 0x00000FFF)
+
+ mov32 r3, tegra_phys_sleep_sp @ per-CPU phys SP save area
+
+#ifdef CONFIG_SMP
+ ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
+ ALT_UP(mov lr, #0)
+ and lr, lr, #15
+#else
+ mov lr, #0
+#endif
+
+ /* Save the normal PRRR value */
+ mrc p15, 0, r0, c10, c2, 0 @ PRRR
+
+ /* Override all remappings to strongly ordered */
+ mov r1, #0
+ mcr p15, 0, r1, c10, c2, 0 @ PRRR
+ mcr p15, 0, r1, c8, c7, 0 @ invalidate local TLBs
+ dsb
+ isb
+
+ /* Save the physical stack pointer */
+ str r2, [r3, lr, lsl #2] @ save phys SP
+
+ /* Restore the regular remappings */
+ mcr p15, 0, r0, c10, c2, 0 @ PRRR
+ mcr p15, 0, r1, c8, c7, 0 @ invalidate local TLBs
+ dsb
+ isb
+#else
+ /* Use the standard cpu_suspend. */
+ adr r3, BSYM(tegra_finish_suspend)
+ b __cpu_suspend
+
+tegra_finish_suspend:
+ /* Turn off SMP coherency */
+ exit_smp r1, r6
+#endif
+ mov pc, r9
+ENDPROC(tegra_cpu_suspend)
+
+/*
+ * tegra_cpu_save
+ *
+ * Input:
+ * r0 = v:p offset
+ * r12 = return to the caller of this function
+ * Output:
+ * r0 = v:p offset
+ * r7 = SP after saving the registers but before cpu_suspend, suitable
+ * for restoring an aborted suspend
+ * sp = SP after tegra_cpu_suspend (the 'real' SP)
+ * Saves r4-r11 on the stack
+ * Corrupts r1, r3-r11
+ */
+
+ENTRY(tegra_cpu_save)
+ push_ctx_regs r1 @ save context registers
+
+ mov r7, sp @ SP after reg save, before suspend
+
+#if USE_TEGRA_CPU_SUSPEND
+ cpu_id r4
+ mov32 r5, tegra_cpu_context @ address of non-cacheable context page
+ ldr r5, [r5] @ non-cacheable context save area
+ mov r6, #0x400 @ size of one CPU context stack area
+ add r4, r4, #1
+ smlabb sp, r6, r4, r5 @ context area for this CPU
+ push_stack_token r4 @ debug check word
+ stmfd sp!, {r7} @ save the real stack pointer
+ push_stack_token r4 @ debug check word
+#endif
+
+ mov r4, r12
+ mov r8, r0
+ mov r11, r2
+ mov r1, r0
+ bl tegra_cpu_suspend
+ mov r0, r8
+ mov r2, r11
+ mov pc, r4
+ENDPROC(tegra_cpu_save)
+
+/*
+ * tegra_sleep_cpu_save(unsigned long v2p)
*
* enters suspend in LP2 by turning off the mmu and jumping to
* tegra?_tear_down_cpu
*/
-ENTRY(tegra_sleep_cpu_finish)
- bl tegra_cpu_exit_coherency
+ENTRY(tegra_sleep_cpu_save)
+ mov r12, pc @ return here is via r12
+ b tegra_cpu_save
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
mov32 r1, tegra2_tear_down_cpu
@@ -146,7 +358,35 @@ ENTRY(tegra_sleep_cpu_finish)
#endif
add r1, r1, r0
b tegra_turn_off_mmu
-ENDPROC(tegra_sleep_cpu_finish)
+ENDPROC(tegra_sleep_cpu_save)
+
+/*
+ * tegra_cpu_resume
+ *
+ * reloads the volatile CPU state from the context area
+ * initializes the processor mode stacks
+ * the mmu should be on and the CPU should be coherent before this is called
+ */
+ .align L1_CACHE_SHIFT
+tegra_cpu_resume:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c3, 0 @ invalidate TLB
+ mcr p15, 0, r0, c7, c5, 6 @ flush BTAC
+ mcr p15, 0, r0, c7, c5, 0 @ flush instruction cache
+ dsb
+ isb
+
+#if USE_TEGRA_CPU_SUSPEND
+ pop_stack_token r4, r5 @ check stack debug token
+ ldmfd sp!, {r0} @ get the real stack pointer
+ pop_stack_token r4, r5 @ check stack debug token
+ mov sp, r0 @ switch to the real stack pointer
+#endif
+
+ bl cpu_init
+
+ pop_ctx_regs r1, r2 @ restore context registers
+ mov pc, lr
/*
* tegra_turn_off_mmu
@@ -155,27 +395,6 @@ ENDPROC(tegra_sleep_cpu_finish)
* r1 = physical address to jump to with mmu off
*/
ENTRY(tegra_turn_off_mmu)
- /*
- * change page table pointer to tegra_pgd_phys, so that IRAM
- * and MMU shut-off will be mapped virtual == physical
- */
- mrc p15, 0, r2, c2, c0, 0 @ TTB 0
- mov32 r3, ~PAGE_MASK
- and r2, r2, r3
- ldr r3, tegra_pgd_phys_address
- ldr r3, [r3]
- orr r3, r3, r2
- mov r2, #0
- mcr p15, 0, r2, c13, c0, 1 @ reserved context
- isb
- mcr p15, 0, r3, c2, c0, 0 @ TTB 0
- isb
-
- mov r2, #0
- mcr p15, 0, r2, c8, c3, 0 @ invalidate TLB
- mcr p15, 0, r2, c7, c5, 6 @ flush BTAC
- mcr p15, 0, r2, c7, c5, 0 @ flush instruction cache
-
mov32 r3, tegra_shut_off_mmu
add r3, r3, r0
mov r0, r1
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 59298f1efbe9..2557c3f687a8 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -25,6 +25,11 @@
#include <mach/iomap.h>
+#ifdef CONFIG_CACHE_L2X0
+#define USE_TEGRA_CPU_SUSPEND 1
+#else
+#define USE_TEGRA_CPU_SUSPEND 0
+#endif
#ifndef CONFIG_TRUSTED_FOUNDATIONS
/* FIXME: The code associated with this should be removed if our change to
save the diagnostic regsiter in the CPU context is accepted. */
@@ -123,6 +128,61 @@
#endif
.endm
+.macro push_ctx_regs, tmp1
+ push_stack_token \tmp1 @ debug check word
+ stmfd sp!, {r4 - r11, lr}
+ /* Save the current TTB0 and CONTEXTID registers. */
+ mrc p15, 0, r5, c2, c0, 0 @ TTB 0
+ mrc p15, 0, r6, c13, c0, 1 @ CONTEXTID
+#if USE_TEGRA_DIAG_REG_SAVE
+ mrc p15, 0, r4, c15, c0, 1 @ read diagnostic register
+ stmfd sp!, {r4-r6}
+#else
+ stmfd sp!, {r5-r6}
+#endif
+ /* Switch to the tegra_pgd so that IRAM and the MMU shut-off code
+ will be flat mapped (VA==PA). We also do this because the common
+ ARM CPU state save/restore code doesn't support an external L2
+ cache controller. If the current PGD is left active, the common
+ ARM MMU restore may (and eventually will) damage the currently
+ running page tables by adding a temporary flat section mapping
+ that could be picked up by other CPUs from the L2 cache
+ resulting in a kernel panic. */
+ ldr r6, tegra_pgd_phys_address
+ ldr r6, [r6]
+ mov r7, #0
+ dsb
+ mcr p15, 0, r7, c13, c0, 1 @ CONTEXTID = reserved context
+ isb
+ mcr p15, 0, r6, c2, c0, 0 @ TTB 0
+ isb
+ mcr p15, 0, r7, c8, c3, 0 @ invalidate TLB
+ mcr p15, 0, r7, c7, c5, 6 @ flush BTAC
+ mcr p15, 0, r7, c7, c5, 0 @ flush instruction cache
+ dsb
+.endm
+
+.macro pop_ctx_regs, tmp1, tmp2
+#if USE_TEGRA_DIAG_REG_SAVE
+ ldmfd sp!, {r4-r6}
+ mcr p15, 0, r4, c15, c0, 1 @ write diagnostic register
+#else
+ ldmfd sp!, {r5-r6}
+#endif
+ dsb
+ mcr p15, 0, r5, c2, c0, 0 @ TTB 0
+ isb
+ mcr p15, 0, r6, c13, c0, 1 @ CONTEXTID = reserved context
+ isb
+ mov r7, #0
+ mcr p15, 0, r7, c8, c3, 0 @ invalidate TLB
+ mcr p15, 0, r7, c7, c5, 6 @ flush BTAC
+ mcr p15, 0, r7, c7, c5, 0 @ flush instruction cache
+ dsb
+ ldmfd sp!, {r4 - r11, lr}
+ pop_stack_token \tmp1, \tmp2 @ debug stack debug token
+.endm
+
#else /* !defined(__ASSEMBLY__) */
#define FLOW_CTRL_HALT_CPU(cpu) (IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + \
@@ -145,9 +205,8 @@ static inline void flowctrl_writel(unsigned long val, void __iomem *addr)
void tegra_pen_lock(void);
void tegra_pen_unlock(void);
void tegra_cpu_wfi(void);
-int tegra_sleep_cpu_finish(unsigned long v2p);
+void tegra_sleep_cpu_save(unsigned long v2p);
void tegra_resume(void);
-void tegra_cpu_resume(void);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
extern void tegra2_iram_start;
@@ -156,14 +215,14 @@ int tegra2_cpu_is_resettable_soon(void);
void tegra2_cpu_reset(int cpu);
void tegra2_cpu_set_resettable_soon(void);
void tegra2_cpu_clear_resettable(void);
-int tegra2_sleep_core_finish(unsigned long int);
+void tegra2_sleep_core(unsigned long v2p);
void tegra2_hotplug_shutdown(void);
void tegra2_sleep_wfi(unsigned long v2p);
#else
extern void tegra3_iram_start;
extern void tegra3_iram_end;
-int tegra3_sleep_core_finish(unsigned long int);
-int tegra3_sleep_cpu_secondary_finish(unsigned long int);
+void tegra3_sleep_core(unsigned long v2p);
+void tegra3_sleep_cpu_secondary(unsigned long v2p);
void tegra3_hotplug_shutdown(void);
#endif
diff --git a/arch/arm/mach-tegra/syncpt.c b/arch/arm/mach-tegra/syncpt.c
deleted file mode 100644
index 8ebab3801a8a..000000000000
--- a/arch/arm/mach-tegra/syncpt.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Erik Gilling <konkers@google.com>
- *
- * Copyright (C) 2010, NVIDIA Corporation
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-
-#define HOST1X_SYNC_OFFSET 0x3000
-#define HOST1X_SYNC_SIZE 0x800
-enum {
- HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS = 0x40,
- HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE = 0x60
-};
-
-static void syncpt_thresh_mask(struct irq_data *data)
-{
- (void)data;
-}
-
-static void syncpt_thresh_unmask(struct irq_data *data)
-{
- (void)data;
-}
-
-static void syncpt_thresh_cascade(unsigned int irq, struct irq_desc *desc)
-{
- void __iomem *sync_regs = irq_desc_get_handler_data(desc);
- unsigned long reg;
- int id;
- struct irq_chip *chip = irq_desc_get_chip(desc);
-
- chained_irq_enter(chip, desc);
-
- reg = readl(sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
-
- for_each_set_bit(id, &reg, 32)
- generic_handle_irq(id + INT_SYNCPT_THRESH_BASE);
-
- chained_irq_exit(chip, desc);
-}
-
-static struct irq_chip syncpt_thresh_irq = {
- .name = "syncpt",
- .irq_mask = syncpt_thresh_mask,
- .irq_unmask = syncpt_thresh_unmask
-};
-
-static int __init syncpt_init_irq(void)
-{
- void __iomem *sync_regs;
- unsigned int i;
- int irq;
-
- sync_regs = ioremap(TEGRA_HOST1X_BASE + HOST1X_SYNC_OFFSET,
- HOST1X_SYNC_SIZE);
- BUG_ON(!sync_regs);
-
- writel(0xffffffffUL,
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
- writel(0xffffffffUL,
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
-
- for (i = 0; i < INT_SYNCPT_THRESH_NR; i++) {
- irq = INT_SYNCPT_THRESH_BASE + i;
- irq_set_chip_and_handler(irq, &syncpt_thresh_irq,
- handle_simple_irq);
- irq_set_chip_data(irq, sync_regs);
- set_irq_flags(irq, IRQF_VALID);
- }
- irq_set_chained_handler(INT_HOST1X_MPCORE_SYNCPT,
- syncpt_thresh_cascade);
- irq_set_handler_data(INT_HOST1X_MPCORE_SYNCPT, sync_regs);
-
- return 0;
-}
-
-core_initcall(syncpt_init_irq);
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 126a1d56591a..af30cf2ea18c 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2485,10 +2485,12 @@ struct clk tegra_list_periph_clks[] = {
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 0x31E, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 0x31E, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 0x31E, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usbd", "tegra-udc.0", NULL, 22, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("dsia", "tegradc.0", "dsia", 48, 0, 0x31E, 500000000, mux_plld_out0, 0), /* scales with voltage */
+ PERIPH_CLK("dsi1-fixed", "tegradc.0", "dsi-fixed", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("dsi2-fixed", "tegradc.1", "dsi-fixed", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 0x31E, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 0x31E, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 0x31E, 150000000, mux_clk_m, PERIPH_NO_RESET),
@@ -2502,7 +2504,7 @@ struct clk tegra_list_shared_clks[] = {
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("mon.sclk", "tegra-stat-mon", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("bsea.sclk", "tegra-aes", "sclk", &tegra_clk_virtual_sclk),
- SHARED_CLK("usbd.sclk", "fsl-tegra-udc", "sclk", &tegra_clk_virtual_sclk),
+ SHARED_CLK("usbd.sclk", "tegra-udc.0", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("usb1.sclk", "tegra-ehci.0", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("usb2.sclk", "tegra-ehci.1", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("usb3.sclk", "tegra-ehci.2", "sclk", &tegra_clk_virtual_sclk),
@@ -2518,7 +2520,7 @@ struct clk tegra_list_shared_clks[] = {
SHARED_CLK("3d.emc", "tegra_gr3d", "emc", &tegra_clk_emc),
SHARED_CLK("2d.emc", "tegra_gr2d", "emc", &tegra_clk_emc),
SHARED_CLK("mpe.emc", "tegra_mpe", "emc", &tegra_clk_emc),
- SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc),
+ SHARED_CLK("usbd.emc", "tegra-udc.0", "emc", &tegra_clk_emc),
SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc),
SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc),
SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc),
@@ -2897,11 +2899,170 @@ static struct syscore_ops tegra_clk_syscore_ops = {
.resume = tegra_clk_resume,
};
+#ifdef CONFIG_TEGRA_PREINIT_CLOCKS
+
+#define RST_DEVICES_L RST_DEVICES
+#define CLK_OUT_ENB_L 0x010
+#define CLK_RSTENB_L_HOST1X_BIT (1 << 28)
+#define CLK_RSTENB_L_DISP1_BIT (1 << 27)
+#define CLK_RSTENB_L_3D_BIT (1 << 24)
+#define CLK_RSTENB_L_2D_BIT (1 << 21)
+#define CLK_RSTENB_L_VI_BIT (1 << 20)
+#define CLK_RSTENB_L_EPP_BIT (1 << 19)
+
+#define RST_DEVICES_H 0x008
+#define CLK_OUT_ENB_H 0x014
+#define CLK_RSTENB_H_MPE_BIT (1 << 28)
+
+#define GCLK_SRC_SHIFT 30
+#define GCLK_SRC_MASK (0x3 << GCLK_SRC_SHIFT)
+#define GCLK_SRC_PLLM_OUT0 0
+#define GCLK_SRC_PLLC_OUT0 1
+#define GCLK_SRC_PLLP_OUT0 2
+#define GCLK_SRC_PLLA_OUT0 3
+#define GCLK_IDLE_DIV_SHIFT 8
+#define GCLK_IDLE_DIV_MASK (0xff << GCLK_IDLE_DIV_SHIFT)
+#define GCLK_DIV_SHIFT 0
+#define GCLK_DIV_MASK (0xff << GCLK_DIV_SHIFT)
+
+#define DISP1_CLK_REG 0x138
+#define DCLK_SRC_PLLP_OUT0 0
+#define DCLK_SRC_PLLD_OUT0 1
+#define DCLK_SRC_PLLC_OUT0 2
+#define DCLK_SRC_CLKM 3
+#define DISP1_CLK_SRC (DCLK_SRC_PLLC_OUT0 << GCLK_SRC_SHIFT)
+
+#define HOST1X_CLK_REG 0x180
+#define HOST1X_CLK_SRC (GCLK_SRC_PLLP_OUT0 << GCLK_SRC_SHIFT)
+#define HOST1X_CLK_IDLE_DIV (0 << GCLK_IDLE_DIV_SHIFT)
+#define HOST1X_CLK_DIV (3 << GCLK_DIV_SHIFT)
+
+#define G3D_CLK_REG 0x158
+#define G3D_CLK_SRC (GCLK_SRC_PLLC_OUT0 << GCLK_SRC_SHIFT)
+#define G3D_CLK_IDLE_DIV (0 << GCLK_IDLE_DIV_SHIFT)
+#define G3D_CLK_DIV (0xa << GCLK_DIV_SHIFT)
+
+#define G2D_CLK_REG 0x15c
+#define G2D_CLK_SRC (GCLK_SRC_PLLC_OUT0 << GCLK_SRC_SHIFT)
+#define G2D_CLK_IDLE_DIV (0 << GCLK_IDLE_DIV_SHIFT)
+#define G2D_CLK_DIV (0xa << GCLK_DIV_SHIFT)
+
+#define VI_CLK_REG 0x148
+#define VI_CLK_SRC (GCLK_SRC_PLLC_OUT0 << GCLK_SRC_SHIFT)
+#define VI_CLK_DIV (0xa << GCLK_DIV_SHIFT)
+
+#define EPP_CLK_REG 0x16c
+#define EPP_CLK_SRC (GCLK_SRC_PLLC_OUT0 << GCLK_SRC_SHIFT)
+#define EPP_CLK_DIV (0xa << GCLK_DIV_SHIFT)
+
+#define MPE_CLK_REG 0x170
+#define MPE_CLK_SRC (GCLK_SRC_PLLC_OUT0 << GCLK_SRC_SHIFT)
+#define MPE_CLK_DIV (0xa << GCLK_DIV_SHIFT)
+
+static void __init clk_setbit(u32 reg, u32 bit)
+{
+ u32 val = clk_readl(reg);
+
+ if ((val & bit) == bit)
+ return;
+ val |= bit;
+ clk_writel(val, reg);
+ udelay(2);
+}
+
+static void __init clk_clrbit(u32 reg, u32 bit)
+{
+ u32 val = clk_readl(reg);
+
+ if ((val & bit) == 0)
+ return;
+ val &= ~bit;
+ clk_writel(val, reg);
+ udelay(2);
+}
+
+static void __init clk_setbits(u32 reg, u32 bits, u32 mask)
+{
+ u32 val = clk_readl(reg);
+
+ if ((val & mask) == bits)
+ return;
+ val &= ~mask;
+ val |= bits;
+ clk_writel(val, reg);
+ udelay(2);
+}
+
+static int __init tegra_soc_preinit_clocks(void)
+{
+ /* vi: */
+ clk_setbit(RST_DEVICES_L, CLK_RSTENB_L_VI_BIT);
+ clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_L_VI_BIT);
+ clk_setbits(VI_CLK_REG, VI_CLK_SRC, GCLK_SRC_MASK);
+ clk_setbits(VI_CLK_REG, VI_CLK_DIV, GCLK_DIV_MASK);
+ clk_clrbit(RST_DEVICES_L, CLK_RSTENB_L_VI_BIT);
+
+ /* 3d: */
+ clk_setbit(RST_DEVICES_L, CLK_RSTENB_L_3D_BIT);
+ clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_L_3D_BIT);
+ clk_setbits(G3D_CLK_REG, G3D_CLK_SRC, GCLK_SRC_MASK);
+ clk_setbits(G3D_CLK_REG, G3D_CLK_IDLE_DIV, GCLK_IDLE_DIV_MASK);
+ clk_setbits(G3D_CLK_REG, G3D_CLK_DIV, GCLK_DIV_MASK);
+ clk_clrbit(RST_DEVICES_L, CLK_RSTENB_L_3D_BIT);
+
+ /* 2d: */
+ clk_setbit(RST_DEVICES_L, CLK_RSTENB_L_2D_BIT);
+ clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_L_2D_BIT);
+ clk_setbits(G2D_CLK_REG, G2D_CLK_SRC, GCLK_SRC_MASK);
+ clk_setbits(G2D_CLK_REG, G2D_CLK_IDLE_DIV, GCLK_IDLE_DIV_MASK);
+ clk_setbits(G2D_CLK_REG, G2D_CLK_DIV, GCLK_DIV_MASK);
+ clk_clrbit(RST_DEVICES_L, CLK_RSTENB_L_2D_BIT);
+
+ /* epp: */
+ clk_setbit(RST_DEVICES_L, CLK_RSTENB_L_EPP_BIT);
+ clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_L_EPP_BIT);
+ clk_setbits(EPP_CLK_REG, EPP_CLK_SRC, GCLK_SRC_MASK);
+ clk_setbits(EPP_CLK_REG, EPP_CLK_DIV, GCLK_DIV_MASK);
+ clk_clrbit(RST_DEVICES_L, CLK_RSTENB_L_EPP_BIT);
+
+ /* mpe: */
+ clk_setbit(RST_DEVICES_H, CLK_RSTENB_H_MPE_BIT);
+ clk_setbit(CLK_OUT_ENB_H, CLK_RSTENB_H_MPE_BIT);
+ clk_setbits(MPE_CLK_REG, MPE_CLK_SRC, GCLK_SRC_MASK);
+ clk_setbits(MPE_CLK_REG, MPE_CLK_DIV, GCLK_DIV_MASK);
+ clk_clrbit(RST_DEVICES_H, CLK_RSTENB_H_MPE_BIT);
+
+ /*
+ * Make sure host1x clock configuration has:
+ * HOST1X_CLK_SRC : PLLP_OUT0.
+ * HOST1X_CLK_DIVISOR: >2 to start from safe enough frequency.
+ */
+ clk_setbit(RST_DEVICES_L, CLK_RSTENB_L_HOST1X_BIT);
+ clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_L_HOST1X_BIT);
+ clk_setbits(HOST1X_CLK_REG, HOST1X_CLK_DIV, GCLK_DIV_MASK);
+ clk_setbits(HOST1X_CLK_REG, HOST1X_CLK_IDLE_DIV, GCLK_IDLE_DIV_MASK);
+ clk_setbits(HOST1X_CLK_REG, HOST1X_CLK_SRC, GCLK_SRC_MASK);
+ clk_clrbit(RST_DEVICES_L, CLK_RSTENB_L_HOST1X_BIT);
+
+ /* DISP1_CLK_SRC: DCLK_SRC_PLLP_OUT0 */
+ clk_setbit(RST_DEVICES_L, CLK_RSTENB_L_DISP1_BIT);
+ clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_L_DISP1_BIT);
+ clk_setbits(DISP1_CLK_REG, DISP1_CLK_SRC, GCLK_SRC_MASK);
+ clk_clrbit(RST_DEVICES_L, CLK_RSTENB_L_DISP1_BIT);
+
+ return 0;
+}
+#endif /* CONFIG_TEGRA_PREINIT_CLOCKS */
+
void __init tegra_soc_init_clocks(void)
{
int i;
struct clk *c;
+#ifdef CONFIG_TEGRA_PREINIT_CLOCKS
+ tegra_soc_preinit_clocks();
+#endif /* CONFIG_TEGRA_PREINIT_CLOCKS */
+
for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
tegra2_init_one_clock(tegra_ptr_clks[i]);
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 0bceeeb9469f..2dfdb1db39b7 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -830,10 +830,6 @@ static int tegra3_cpu_clk_set_rate(struct clk *c, unsigned long rate)
bool skip_to_backup =
skip && (clk_get_rate_all_locked(c) >= SKIPPER_ENGAGE_RATE);
- /* Hardware clock control is not possible on FPGA platforms.
- Report success so that upper level layers don't complain
- needlessly. */
-#ifndef CONFIG_TEGRA_FPGA_PLATFORM
if (c->dvfs) {
if (!c->dvfs->dvfs_rail)
return -ENOSYS;
@@ -912,7 +908,6 @@ out:
tegra3_super_clk_skipper_update(c->parent, 2, 1);
}
clk_disable(c->u.cpu.main);
-#endif
return ret;
}
@@ -3007,12 +3002,17 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
list_for_each_entry(c, &bus->shared_bus_list,
u.shared_bus_user.node) {
- /* Ignore requests from disabled users and from users with
- fixed bus-to-client ratio */
- if (c->u.shared_bus_user.enabled) {
+ /* Ignore requests from disabled floor and bw users, and from
+ * auto-users riding the bus. Always honor ceiling users, even
+ * if they are disabled - we do not want to keep enabled parent
+ * bus just because ceiling is set.
+ */
+ if (c->u.shared_bus_user.enabled ||
+ (c->u.shared_bus_user.mode == SHARED_CEILING)) {
switch (c->u.shared_bus_user.mode) {
case SHARED_BW:
- bw += c->u.shared_bus_user.rate;
+ if (bw < bus->max_rate)
+ bw += c->u.shared_bus_user.rate;
break;
case SHARED_CEILING:
ceiling = min(c->u.shared_bus_user.rate,
@@ -3025,6 +3025,16 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
}
}
}
+
+ if (bw) {
+ if (bus->flags & PERIPH_EMC_ENB) {
+ bw = tegra_emc_bw_efficiency ?
+ (bw / tegra_emc_bw_efficiency) : bus->max_rate;
+ bw = (bw < bus->max_rate / 100) ?
+ (bw * 100) : bus->max_rate;
+ }
+ bw = clk_round_rate_locked(bus, bw);
+ }
rate = min(max(rate, bw), ceiling);
old_rate = clk_get_rate_locked(bus);
@@ -3073,6 +3083,10 @@ static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
if (c->u.shared_bus_user.mode == SHARED_AUTO)
rate = 0;
+ /* BW users should not be rounded until aggregated */
+ if (c->u.shared_bus_user.mode == SHARED_BW)
+ return rate;
+
return clk_round_rate(c->parent, rate);
}
@@ -3958,7 +3972,7 @@ static struct clk tegra_clk_pclk = {
.reg_shift = 0,
.ops = &tegra_bus_ops,
.max_rate = 167000000,
- .min_rate = 12000000,
+ .min_rate = 40000000,
};
static struct raw_notifier_head sbus_rate_change_nh;
@@ -4275,11 +4289,13 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usbd", "tegra-udc.0", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0),
PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops),
+ PERIPH_CLK("dsi1-fixed", "tegradc.0", "dsi-fixed", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("dsi2-fixed", "tegradc.1", "dsi-fixed", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
@@ -4297,7 +4313,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("bsea.sclk", "tegra-aes", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
- SHARED_CLK("usbd.sclk", "fsl-tegra-udc", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
+ SHARED_CLK("usbd.sclk", "tegra-udc.0", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb1.sclk", "tegra-ehci.0", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb2.sclk", "tegra-ehci.1", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb3.sclk", "tegra-ehci.2", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
@@ -4317,7 +4333,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc, NULL, 0, 0),
- SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("usbd.emc", "tegra-udc.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc, NULL, 0, 0),
@@ -4326,7 +4342,8 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("3d.emc", "tegra_gr3d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("2d.emc", "tegra_gr2d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("mpe.emc", "tegra_mpe", "emc", &tegra_clk_emc, NULL, 0, 0),
- SHARED_CLK("camera.emc", "tegra_camera", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("camera.emc", "tegra_camera", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
+ SHARED_CLK("sdmmc4.emc", "sdhci-tegra.3", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("floor.emc", "floor.emc", NULL, &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("host1x.cbus", "tegra_host1x", "host1x", &tegra_clk_cbus, "host1x", 2, SHARED_AUTO),
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index 48c4384b1aac..657a6cfd6510 100644
--- a/arch/arm/mach-tegra/tegra3_dvfs.c
+++ b/arch/arm/mach-tegra/tegra3_dvfs.c
@@ -33,10 +33,10 @@ static bool tegra_dvfs_core_disabled;
static struct dvfs *cpu_dvfs;
static const int cpu_millivolts[MAX_DVFS_FREQS] = {
- 800, 825, 850, 875, 900, 912, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237};
+ 800, 825, 850, 875, 900, 916, 950, 975, 1000, 1007, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237};
static const unsigned int cpu_cold_offs_mhz[MAX_DVFS_FREQS] = {
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};
static const int core_millivolts[MAX_DVFS_FREQS] = {
950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350};
@@ -141,57 +141,59 @@ static struct dvfs_relationship tegra3_dvfs_relationships[] = {
}
static struct dvfs cpu_dvfs_table[] = {
- /* Cpu voltages (mV): 800, 825, 850, 875, 900, 912, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237 */
- CPU_DVFS("cpu_g", 0, 0, MHZ, 1, 1, 684, 684, 817, 817, 1026, 1102, 1149, 1187, 1225, 1282, 1300),
- CPU_DVFS("cpu_g", 0, 1, MHZ, 1, 1, 807, 807, 948, 948, 1117, 1171, 1206, 1300),
- CPU_DVFS("cpu_g", 0, 2, MHZ, 1, 1, 883, 883, 1039, 1039, 1178, 1206, 1300),
- CPU_DVFS("cpu_g", 0, 3, MHZ, 1, 1, 931, 931, 1102, 1102, 1216, 1300),
-
- CPU_DVFS("cpu_g", 1, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1280, 1300),
- CPU_DVFS("cpu_g", 1, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1300),
- CPU_DVFS("cpu_g", 1, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1300),
- CPU_DVFS("cpu_g", 1, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1300),
-
- CPU_DVFS("cpu_g", 2, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
- CPU_DVFS("cpu_g", 2, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1280, 1300, 1350, 1400),
- CPU_DVFS("cpu_g", 2, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1300, 1350, 1400),
-
- CPU_DVFS("cpu_g", 3, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
- CPU_DVFS("cpu_g", 3, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1280, 1300, 1350, 1400),
- CPU_DVFS("cpu_g", 3, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1300, 1350, 1400),
-
- CPU_DVFS("cpu_g", 4, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1240, 1280, 1320, 1360, 1360, 1500),
- CPU_DVFS("cpu_g", 4, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1250, 1300, 1330, 1360, 1400, 1500),
- CPU_DVFS("cpu_g", 4, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1280, 1300, 1340, 1380, 1500),
- CPU_DVFS("cpu_g", 4, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1500),
-
- CPU_DVFS("cpu_g", 5, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 5, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
-
- CPU_DVFS("cpu_g", 6, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 6, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
-
- CPU_DVFS("cpu_g", 7, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1280, 1300),
- CPU_DVFS("cpu_g", 7, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1300),
- CPU_DVFS("cpu_g", 7, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1300),
- CPU_DVFS("cpu_g", 7, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1300),
- CPU_DVFS("cpu_g", 7, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1300),
-
- CPU_DVFS("cpu_g", 8, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1280, 1300),
- CPU_DVFS("cpu_g", 8, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1300),
- CPU_DVFS("cpu_g", 8, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1300),
- CPU_DVFS("cpu_g", 8, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1300),
- CPU_DVFS("cpu_g", 8, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1300),
-
- CPU_DVFS("cpu_g", 9, -1, MHZ, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900),
- CPU_DVFS("cpu_g", 10, -1, MHZ, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
- CPU_DVFS("cpu_g", 11, -1, MHZ, 1, 1, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600),
-
- CPU_DVFS("cpu_g", 12, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 12, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
-
- CPU_DVFS("cpu_g", 13, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 13, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+ /* Cpu voltages (mV): 800, 825, 850, 875, 900, 916, 950, 975, 1000, 1007, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237 */
+ CPU_DVFS("cpu_g", 0, 0, MHZ, 1, 1, 684, 684, 817, 817, 817, 1026, 1102, 1102, 1149, 1187, 1225, 1282, 1300),
+ CPU_DVFS("cpu_g", 0, 1, MHZ, 1, 1, 807, 807, 948, 948, 948, 1117, 1171, 1171, 1206, 1300),
+ CPU_DVFS("cpu_g", 0, 2, MHZ, 1, 1, 883, 883, 1039, 1039, 1039, 1178, 1206, 1206, 1300),
+ CPU_DVFS("cpu_g", 0, 3, MHZ, 1, 1, 931, 931, 1102, 1102, 1102, 1216, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 1, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1280, 1300),
+ CPU_DVFS("cpu_g", 1, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1300),
+ CPU_DVFS("cpu_g", 1, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1300),
+ CPU_DVFS("cpu_g", 1, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1300),
+
+ CPU_DVFS("cpu_g", 2, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
+ CPU_DVFS("cpu_g", 2, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1280, 1300, 1350, 1400),
+ CPU_DVFS("cpu_g", 2, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1300, 1350, 1400),
+
+ CPU_DVFS("cpu_g", 3, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
+ CPU_DVFS("cpu_g", 3, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1280, 1300, 1350, 1400),
+ CPU_DVFS("cpu_g", 3, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1300, 1350, 1400),
+
+ CPU_DVFS("cpu_g", 4, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1240, 1280, 1320, 1360, 1360, 1500),
+ CPU_DVFS("cpu_g", 4, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1250, 1300, 1330, 1360, 1400, 1500),
+ CPU_DVFS("cpu_g", 4, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1280, 1300, 1340, 1380, 1500),
+ CPU_DVFS("cpu_g", 4, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1500),
+
+ CPU_DVFS("cpu_g", 5, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 5, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 6, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 6, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 7, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1280, 1300),
+ CPU_DVFS("cpu_g", 7, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1300),
+ CPU_DVFS("cpu_g", 7, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1300),
+ CPU_DVFS("cpu_g", 7, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1300),
+ CPU_DVFS("cpu_g", 7, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 8, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1280, 1300),
+ CPU_DVFS("cpu_g", 8, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1300),
+ CPU_DVFS("cpu_g", 8, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1300),
+ CPU_DVFS("cpu_g", 8, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1300),
+ CPU_DVFS("cpu_g", 8, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 9, -1, MHZ, 1, 1, 1, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 10, -1, MHZ, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 11, -1, MHZ, 1, 1, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600),
+ CPU_DVFS("cpu_g", 14, -1, MHZ, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 15, -1, MHZ, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+
+ CPU_DVFS("cpu_g", 12, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 12, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 13, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 13, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
/*
* "Safe entry" to be used when no match for chip speedo, process
@@ -228,7 +230,7 @@ static struct dvfs core_dvfs_table[] = {
CORE_DVFS("sbus", 0, 1, KHZ, 1, 136000, 164000, 191000, 216000, 216000, 216000, 216000, 216000),
CORE_DVFS("sbus", 1, 1, KHZ, 51000, 205000, 205000, 227000, 227000, 267000, 267000, 267000, 267000),
CORE_DVFS("sbus", 2, 1, KHZ, 51000, 205000, 205000, 227000, 227000, 267000, 334000, 334000, 334000),
- CORE_DVFS("sbus", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 378000, 378000, 378000),
+ CORE_DVFS("sbus", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 334000, 334000, 334000),
CORE_DVFS("vi", 0, 1, KHZ, 1, 216000, 285000, 300000, 300000, 300000, 300000, 300000, 300000),
CORE_DVFS("vi", 1, 1, KHZ, 1, 216000, 267000, 300000, 371000, 409000, 409000, 409000, 409000),
@@ -275,7 +277,7 @@ static struct dvfs core_dvfs_table[] = {
CORE_DVFS("cbus", 0, 1, KHZ, 1, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
CORE_DVFS("cbus", 1, 1, KHZ, 1, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
CORE_DVFS("cbus", 2, 1, KHZ, 1, 247000, 304000, 352000, 400000, 437000, 484000, 520000, 600000),
- CORE_DVFS("cbus", 3, 1, KHZ, 1, 484000, 484000, 484000, 484000, 484000, 484000, 484000, 484000),
+ CORE_DVFS("cbus", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 484000, 484000, 484000),
CORE_DVFS("pll_c", -1, 1, KHZ, 533000, 667000, 667000, 800000, 800000, 1066000, 1066000, 1066000, 1200000),
@@ -783,19 +785,11 @@ static void core_cap_enable(bool enable)
{
int i;
- if (enable) {
+ if (enable)
tegra3_core_cap.refcnt++;
- if (tegra3_core_cap.refcnt == 1)
- for (i = 0; i < ARRAY_SIZE(core_cap_table); i++)
- if (core_cap_table[i].cap_clk)
- clk_enable(core_cap_table[i].cap_clk);
- } else if (tegra3_core_cap.refcnt) {
+ else if (tegra3_core_cap.refcnt)
tegra3_core_cap.refcnt--;
- if (tegra3_core_cap.refcnt == 0)
- for (i = ARRAY_SIZE(core_cap_table) - 1; i >= 0; i--)
- if (core_cap_table[i].cap_clk)
- clk_disable(core_cap_table[i].cap_clk);
- }
+
core_cap_update();
}
diff --git a/arch/arm/mach-tegra/tegra3_emc.c b/arch/arm/mach-tegra/tegra3_emc.c
index 0725980bfa40..2b19848b04f2 100644
--- a/arch/arm/mach-tegra/tegra3_emc.c
+++ b/arch/arm/mach-tegra/tegra3_emc.c
@@ -45,6 +45,8 @@ static bool emc_enable;
#endif
module_param(emc_enable, bool, 0644);
+u8 tegra_emc_bw_efficiency = 35;
+
#define EMC_MIN_RATE_DDR3 25500000
#define EMC_STATUS_UPDATE_TIMEOUT 100
#define TEGRA_EMC_TABLE_MAX_SIZE 16
@@ -350,6 +352,12 @@ static inline void disable_early_ack(u32 mc_override)
override_val |= mc_override & MC_EMEM_ARB_OVERRIDE_EACK_MASK;
}
+static inline void enable_early_ack(u32 mc_override)
+{
+ mc_writel((mc_override | MC_EMEM_ARB_OVERRIDE_EACK_MASK),
+ MC_EMEM_ARB_OVERRIDE);
+}
+
static inline bool dqs_preset(const struct tegra_emc_table *next_timing,
const struct tegra_emc_table *last_timing)
{
@@ -1163,6 +1171,24 @@ int tegra_emc_set_over_temp_state(unsigned long state)
return 0;
}
+int tegra_emc_set_eack_state(unsigned long state)
+{
+ unsigned long flags;
+ u32 mc_override;
+
+ spin_lock_irqsave(&emc_access_lock, flags);
+
+ mc_override = mc_readl(MC_EMEM_ARB_OVERRIDE);
+
+ if (state)
+ enable_early_ack(mc_override);
+ else
+ disable_early_ack(mc_override);
+
+ spin_unlock_irqrestore(&emc_access_lock, flags);
+ return 0;
+}
+
#ifdef CONFIG_DEBUG_FS
static struct dentry *emc_debugfs_root;
@@ -1222,6 +1248,43 @@ static int over_temp_state_set(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(over_temp_state_fops, over_temp_state_get,
over_temp_state_set, "%llu\n");
+static int eack_state_get(void *data, u64 *val)
+{
+ unsigned long flags;
+ u32 mc_override;
+
+ spin_lock_irqsave(&emc_access_lock, flags);
+ mc_override = mc_readl(MC_EMEM_ARB_OVERRIDE);
+ spin_unlock_irqrestore(&emc_access_lock, flags);
+
+ *val = (mc_override & MC_EMEM_ARB_OVERRIDE_EACK_MASK);
+ return 0;
+}
+
+static int eack_state_set(void *data, u64 val)
+{
+ tegra_emc_set_eack_state(val);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(eack_state_fops, eack_state_get,
+ eack_state_set, "%llu\n");
+
+static int efficiency_get(void *data, u64 *val)
+{
+ *val = tegra_emc_bw_efficiency;
+ return 0;
+}
+static int efficiency_set(void *data, u64 val)
+{
+ tegra_emc_bw_efficiency = (val > 100) ? 100 : val;
+ if (emc)
+ tegra_clk_shared_bus_update(emc);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(efficiency_fops, efficiency_get,
+ efficiency_set, "%llu\n");
+
static int __init tegra_emc_debug_init(void)
{
if (!tegra_emc_table)
@@ -1243,6 +1306,14 @@ static int __init tegra_emc_debug_init(void)
emc_debugfs_root, NULL, &over_temp_state_fops))
goto err_out;
+ if (!debugfs_create_file(
+ "eack_state", S_IRUGO | S_IWUGO, emc_debugfs_root, NULL, &eack_state_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("efficiency", S_IRUGO | S_IWUSR,
+ emc_debugfs_root, NULL, &efficiency_fops))
+ goto err_out;
+
return 0;
err_out:
diff --git a/arch/arm/mach-tegra/tegra3_emc.h b/arch/arm/mach-tegra/tegra3_emc.h
index cfde92c1355a..185d77762da2 100644
--- a/arch/arm/mach-tegra/tegra3_emc.h
+++ b/arch/arm/mach-tegra/tegra3_emc.h
@@ -27,6 +27,8 @@
#define TEGRA_EMC_BRIDGE_RATE_MIN 300000000
#define TEGRA_EMC_BRIDGE_MVOLTS_MIN 1200
+extern u8 tegra_emc_bw_efficiency;
+
struct tegra_emc_table {
u8 rev;
unsigned long rate;
@@ -59,6 +61,7 @@ void tegra_emc_dram_type_init(struct clk *c);
int tegra_emc_get_dram_type(void);
int tegra_emc_get_dram_temperature(void);
int tegra_emc_set_over_temp_state(unsigned long state);
+int tegra_emc_set_eack_state(unsigned long state);
#ifdef CONFIG_PM_SLEEP
void tegra_mc_timing_restore(void);
diff --git a/arch/arm/mach-tegra/tegra3_speedo.c b/arch/arm/mach-tegra/tegra3_speedo.c
index bd880bc7ca8b..78afb2804088 100644
--- a/arch/arm/mach-tegra/tegra3_speedo.c
+++ b/arch/arm/mach-tegra/tegra3_speedo.c
@@ -108,8 +108,8 @@ static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
/* T30 Automotives */
/* threshold_index 12: cpu_speedo_id 9 & 10
- * 0,1,2 values correspond to speedo_id 9
- * 3,4,5 values correspond to speedo_id 10 */
+ * 0,1,2 values correspond to speedo_id 9/14
+ * 3,4,5 values correspond to speedo_id 10/15*/
{300, 311, 360, 371, 381, 415, 431},
{300, 311, 410, 431, UINT_MAX}, /* [13]: cpu_speedo_id 11: T30 auto */
@@ -462,10 +462,31 @@ void tegra_init_speedo_data(void)
soc_speedo_id = 1;
}
if (threshold_index == 12 && cpu_process_id != INVALID_PROCESS_ID) {
- if (cpu_process_id <= 2)
- cpu_speedo_id = 9;
- else if (cpu_process_id >= 3 && cpu_process_id < 6)
- cpu_speedo_id = 10;
+ if (cpu_process_id <= 2) {
+ switch(fuse_sku) {
+ case 0xb0:
+ case 0xb1:
+ cpu_speedo_id = 9;
+ break;
+ case 0x90:
+ case 0x91:
+ cpu_speedo_id = 14;
+ default:
+ break;
+ }
+ } else if (cpu_process_id >= 3 && cpu_process_id < 6) {
+ switch(fuse_sku) {
+ case 0xb0:
+ case 0xb1:
+ cpu_speedo_id = 10;
+ break;
+ case 0x90:
+ case 0x91:
+ cpu_speedo_id = 15;
+ default:
+ break;
+ }
+ }
}
pr_info("Tegra3: CPU Speedo ID %d, Soc Speedo ID %d",
cpu_speedo_id, soc_speedo_id);
@@ -510,8 +531,8 @@ int tegra_package_id(void)
* latter is resolved by the dvfs code)
*/
static const int cpu_speedo_nominal_millivolts[] =
-/* speedo_id 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 */
- { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 912, 850, 850, 1237, 1237};
+/* speedo_id 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
+ { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 1007, 916, 850, 1237, 1237, 950, 900};
int tegra_cpu_speedo_mv(void)
{
diff --git a/arch/arm/mach-tegra/tegra3_thermal.c b/arch/arm/mach-tegra/tegra3_thermal.c
index 8ad7bd5b670f..6322eb35ab79 100644
--- a/arch/arm/mach-tegra/tegra3_thermal.c
+++ b/arch/arm/mach-tegra/tegra3_thermal.c
@@ -37,15 +37,13 @@
struct tegra_thermal {
struct tegra_thermal_device *device;
- long temp_throttle_tj;
long temp_shutdown_tj;
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ long temp_throttle_tj;
struct thermal_zone_device *thz;
int tc1;
int tc2;
long passive_delay;
-#else
- long temp_throttle_low_tj;
#endif
#ifdef CONFIG_TEGRA_EDP_LIMITS
int edp_thermal_zone_val;
@@ -62,10 +60,6 @@ static struct tegra_thermal thermal_state = {
#endif
};
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
-static bool throttle_enb;
-#endif
-
#ifdef CONFIG_TEGRA_EDP_LIMITS
static inline long edp2tj(struct tegra_thermal *thermal,
long edp_temp)
@@ -92,7 +86,7 @@ static inline long tj2dev(struct tegra_thermal_device *dev,
return tj_temp - dev->offset;
}
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
static int tegra_thermal_zone_bind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdevice) {
@@ -107,7 +101,7 @@ static int tegra_thermal_zone_unbind(struct thermal_zone_device *thermal,
}
static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
- long *temp)
+ unsigned long *temp)
{
struct tegra_thermal *thermal = thz->devdata;
thermal->device->get_temp(thermal->device->data, temp);
@@ -130,8 +124,8 @@ static int tegra_thermal_zone_get_trip_type(
}
static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
- int trip,
- long *temp) {
+ int trip,
+ unsigned long *temp) {
struct tegra_thermal *thermal = thz->devdata;
/* Support only Thermal Throttling (1 trip) for now */
@@ -152,20 +146,6 @@ static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
};
#endif
-/* The thermal sysfs handles notifying the throttling
- * cooling device */
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
-static void tegra_therm_throttle(bool enable)
-{
- if (throttle_enb != enable) {
- mutex_lock(&thermal_state.mutex);
- tegra_throttling_enable(enable);
- throttle_enb = enable;
- mutex_unlock(&thermal_state.mutex);
- }
-}
-#endif
-
/* Make sure this function remains stateless */
void tegra_thermal_alert(void *data)
{
@@ -187,7 +167,7 @@ void tegra_thermal_alert(void *data)
mutex_lock(&thermal_state.mutex);
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
if (thermal->thz) {
if (!thermal->thz->passive)
thermal_zone_device_update(thermal->thz);
@@ -207,17 +187,11 @@ void tegra_thermal_alert(void *data)
temp_low_tj = dev2tj(thermal->device, temp_low_dev);
lo_limit_throttle_tj = temp_low_tj;
+ hi_limit_throttle_tj = thermal->temp_shutdown_tj;
+
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
hi_limit_throttle_tj = thermal->temp_throttle_tj;
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- /* Check to see if we are currently throttling */
- if ((tegra_is_throttling() &&
- (temp_tj > thermal->temp_throttle_low_tj))
- || (temp_tj >= thermal->temp_throttle_tj)) {
- lo_limit_throttle_tj = thermal->temp_throttle_low_tj;
- hi_limit_throttle_tj = thermal->temp_shutdown_tj;
- }
-#else
if (temp_tj > thermal->temp_throttle_tj) {
lo_limit_throttle_tj = thermal->temp_throttle_tj;
hi_limit_throttle_tj = thermal->temp_shutdown_tj;
@@ -262,18 +236,6 @@ void tegra_thermal_alert(void *data)
tj2dev(thermal->device, lo_limit_tj),
tj2dev(thermal->device, hi_limit_tj));
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- if (temp_tj >= thermal->temp_throttle_tj) {
- /* start throttling */
- if (!tegra_is_throttling())
- tegra_therm_throttle(true);
- } else if (temp_tj <= thermal->temp_throttle_low_tj) {
- /* switch off throttling */
- if (tegra_is_throttling())
- tegra_therm_throttle(false);
- }
-#endif
-
#ifdef CONFIG_TEGRA_EDP_LIMITS
/* inform edp governor */
if (thermal->edp_thermal_zone_val != temp_tj)
@@ -288,7 +250,7 @@ done:
int tegra_thermal_set_device(struct tegra_thermal_device *device)
{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
struct thermal_zone_device *thz;
#endif
@@ -298,7 +260,7 @@ int tegra_thermal_set_device(struct tegra_thermal_device *device)
thermal_state.device = device;
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
thz = thermal_zone_device_register(thermal_state.device->name,
1, /* trips */
&thermal_state,
@@ -330,22 +292,18 @@ int tegra_thermal_set_device(struct tegra_thermal_device *device)
int __init tegra_thermal_init(struct tegra_thermal_data *data)
{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
thermal_state.tc1 = data->tc1;
thermal_state.tc2 = data->tc2;
thermal_state.passive_delay = data->passive_delay;
-#else
- thermal_state.temp_throttle_low_tj = data->temp_throttle +
- data->temp_offset -
- data->hysteresis_throttle;
+ thermal_state.temp_throttle_tj = data->temp_throttle +
+ data->temp_offset;
#endif
mutex_init(&thermal_state.mutex);
#ifdef CONFIG_TEGRA_EDP_LIMITS
thermal_state.edp_offset = data->edp_offset;
thermal_state.hysteresis_edp = data->hysteresis_edp;
#endif
- thermal_state.temp_throttle_tj = data->temp_throttle +
- data->temp_offset;
thermal_state.temp_shutdown_tj = data->temp_shutdown +
data->temp_offset;
@@ -354,7 +312,7 @@ int __init tegra_thermal_init(struct tegra_thermal_data *data)
int tegra_thermal_exit(void)
{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
if (thermal_state.thz)
thermal_zone_device_unregister(thermal_state.thz);
#endif
@@ -364,19 +322,11 @@ int tegra_thermal_exit(void)
#ifdef CONFIG_DEBUG_FS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
static int tegra_thermal_throttle_temp_tj_set(void *data, u64 val)
{
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- long throttle_hysteresis = thermal_state.temp_throttle_tj -
- thermal_state.temp_throttle_low_tj;
-#endif
-
mutex_lock(&thermal_state.mutex);
thermal_state.temp_throttle_tj = val;
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- thermal_state.temp_throttle_low_tj = thermal_state.temp_throttle_tj -
- throttle_hysteresis;
-#endif
mutex_unlock(&thermal_state.mutex);
tegra_thermal_alert(&thermal_state);
@@ -394,6 +344,7 @@ DEFINE_SIMPLE_ATTRIBUTE(throttle_temp_tj_fops,
tegra_thermal_throttle_temp_tj_get,
tegra_thermal_throttle_temp_tj_set,
"%llu\n");
+#endif
static int tegra_thermal_shutdown_temp_tj_set(void *data, u64 val)
{
@@ -447,7 +398,7 @@ DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
NULL,
"%llu\n");
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
static int tegra_thermal_tc1_set(void *data, u64 val)
{
thermal_state.thz->tc1 = val;
@@ -507,10 +458,6 @@ static int __init tegra_thermal_debug_init(void)
{
thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
- if (!debugfs_create_file("throttle_temp_tj", 0644, thermal_debugfs_root,
- NULL, &throttle_temp_tj_fops))
- goto err_out;
-
if (!debugfs_create_file("shutdown_temp_tj", 0644, thermal_debugfs_root,
NULL, &shutdown_temp_tj_fops))
goto err_out;
@@ -519,7 +466,11 @@ static int __init tegra_thermal_debug_init(void)
NULL, &temp_tj_fops))
goto err_out;
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ if (!debugfs_create_file("throttle_temp_tj", 0644, thermal_debugfs_root,
+ NULL, &throttle_temp_tj_fops))
+ goto err_out;
+
if (!debugfs_create_file("tc1", 0644, thermal_debugfs_root,
NULL, &tc1_fops))
goto err_out;
diff --git a/arch/arm/mach-tegra/tegra3_throttle.c b/arch/arm/mach-tegra/tegra3_throttle.c
index f927be7800d6..9e8d32fb79fa 100644
--- a/arch/arm/mach-tegra/tegra3_throttle.c
+++ b/arch/arm/mach-tegra/tegra3_throttle.c
@@ -34,33 +34,26 @@
/* tegra throttling require frequencies in the table to be in ascending order */
static struct cpufreq_frequency_table *cpu_freq_table;
-static struct mutex *cpu_throttle_lock;
static struct {
unsigned int cpu_freq;
int core_cap_level;
- int ms;
} throttle_table[] = {
- { 0, 1000, 2000 }, /* placeholder for cpu floor rate */
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 760000, 1000, 2000 },
- { 760000, 1050, 2000 },
- {1000000, 1050, 2000 },
- {1000000, 1100, 2000 },
+ { 0, 1000 }, /* placeholder for cpu floor rate */
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
};
static int is_throttling;
static int throttle_index;
-static struct delayed_work throttle_work;
-static struct workqueue_struct *workqueue;
-static DEFINE_MUTEX(tegra_throttle_lock);
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
static struct thermal_cooling_device *cdev;
-#endif
static unsigned int clip_to_table(unsigned int cpu_freq)
{
@@ -74,81 +67,6 @@ static unsigned int clip_to_table(unsigned int cpu_freq)
return cpu_freq_table[i].frequency;
}
-static void tegra_throttle_work_func(struct work_struct *work)
-{
- unsigned int cpu_freq;
- int core_level;
-
- mutex_lock(cpu_throttle_lock);
- if (!is_throttling) {
- mutex_unlock(cpu_throttle_lock);
- return;
- }
-
- cpu_freq = tegra_getspeed(0);
- throttle_index -= throttle_index ? 1 : 0;
-
- core_level = throttle_table[throttle_index].core_cap_level;
- if (throttle_table[throttle_index].cpu_freq < cpu_freq)
- tegra_cpu_set_speed_cap(NULL);
-
- if (throttle_index || (throttle_table[0].cpu_freq < cpu_freq))
- queue_delayed_work(workqueue, &throttle_work,
- msecs_to_jiffies(throttle_table[throttle_index].ms));
-
- mutex_unlock(cpu_throttle_lock);
-
- tegra_dvfs_core_cap_level_set(core_level);
-}
-
-/*
- * tegra_throttling_enable
- * This function may sleep
- */
-void tegra_throttling_enable(bool enable)
-{
- mutex_lock(&tegra_throttle_lock);
- mutex_lock(cpu_throttle_lock);
-
- if (enable && !(is_throttling++)) {
- int core_level;
- unsigned int cpu_freq = tegra_getspeed(0);
- throttle_index = ARRAY_SIZE(throttle_table) - 1;
-
- core_level = throttle_table[throttle_index].core_cap_level;
- if (throttle_table[throttle_index].cpu_freq < cpu_freq)
- tegra_cpu_set_speed_cap(NULL);
-
- queue_delayed_work(workqueue, &throttle_work,
- msecs_to_jiffies(throttle_table[throttle_index].ms));
-
- mutex_unlock(cpu_throttle_lock);
-
- tegra_dvfs_core_cap_level_set(core_level);
- tegra_dvfs_core_cap_enable(true);
-
- mutex_unlock(&tegra_throttle_lock);
- return;
- }
-
- if (!enable && is_throttling) {
- if (!(--is_throttling)) {
- /* restore speed requested by governor */
- tegra_cpu_set_speed_cap(NULL);
- mutex_unlock(cpu_throttle_lock);
-
- tegra_dvfs_core_cap_enable(false);
- cancel_delayed_work_sync(&throttle_work);
- mutex_unlock(&tegra_throttle_lock);
- return;
- }
- }
-
- mutex_unlock(cpu_throttle_lock);
- mutex_unlock(&tegra_throttle_lock);
-}
-EXPORT_SYMBOL_GPL(tegra_throttling_enable);
-
unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
{
return is_throttling ?
@@ -161,8 +79,6 @@ bool tegra_is_throttling(void)
return is_throttling;
}
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
-
static int
tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *max_state)
@@ -175,11 +91,9 @@ static int
tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *cur_state)
{
- mutex_lock(cpu_throttle_lock);
*cur_state = is_throttling ?
(ARRAY_SIZE(throttle_table) - throttle_index) :
0;
- mutex_unlock(cpu_throttle_lock);
return 0;
}
@@ -190,7 +104,6 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
{
int core_level;
- mutex_lock(cpu_throttle_lock);
if (cur_state == 0) {
/* restore speed requested by governor */
if (is_throttling) {
@@ -212,7 +125,6 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
tegra_cpu_set_speed_cap(NULL);
}
- mutex_unlock(cpu_throttle_lock);
return 0;
}
@@ -222,7 +134,6 @@ struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
.get_cur_state = tegra_throttle_get_cur_state,
.set_cur_state = tegra_throttle_set_cur_state,
};
-#endif
int __init tegra_throttle_init(struct mutex *cpu_lock)
{
@@ -232,18 +143,6 @@ int __init tegra_throttle_init(struct mutex *cpu_lock)
if (IS_ERR_OR_NULL(table_data))
return -EINVAL;
- /*
- * High-priority, others flags default: not bound to a specific
- * CPU, has rescue worker task (in case of allocation deadlock,
- * etc.). Single-threaded.
- */
- workqueue = alloc_workqueue("cpu-tegra",
- WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
- if (!workqueue)
- return -ENOMEM;
- INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
-
- cpu_throttle_lock = cpu_lock;
cpu_freq_table = table_data->freq_table;
throttle_table[0].cpu_freq =
cpu_freq_table[table_data->throttle_lowest_index].frequency;
@@ -253,7 +152,6 @@ int __init tegra_throttle_init(struct mutex *cpu_lock)
throttle_table[i].cpu_freq = clip_to_table(cpu_freq);
}
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
cdev = thermal_cooling_device_register("Throttle", NULL,
&tegra_throttle_cooling_ops);
@@ -261,44 +159,27 @@ int __init tegra_throttle_init(struct mutex *cpu_lock)
cdev = NULL;
return -ENODEV;
}
-#endif
return 0;
}
void tegra_throttle_exit(void)
{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
if (cdev) {
thermal_cooling_device_unregister(cdev);
cdev = NULL;
}
-#endif
- destroy_workqueue(workqueue);
}
#ifdef CONFIG_DEBUG_FS
-
-static int throttle_debug_set(void *data, u64 val)
-{
- tegra_throttling_enable(val);
- return 0;
-}
-static int throttle_debug_get(void *data, u64 *val)
-{
- *val = (u64) is_throttling;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, throttle_debug_get, throttle_debug_set,
- "%llu\n");
static int table_show(struct seq_file *s, void *data)
{
int i;
for (i = 0; i < ARRAY_SIZE(throttle_table); i++)
- seq_printf(s, "[%d] = %7u %4d %5d\n",
+ seq_printf(s, "[%d] = %7u %4d\n",
i, throttle_table[i].cpu_freq,
- throttle_table[i].core_cap_level, throttle_table[i].ms);
+ throttle_table[i].core_cap_level);
return 0;
}
@@ -314,7 +195,6 @@ static ssize_t table_write(struct file *file,
int table_idx;
unsigned int cpu_freq;
int core_cap_level;
- int ms;
if (sizeof(buf) <= count)
return -EINVAL;
@@ -327,8 +207,8 @@ static ssize_t table_write(struct file *file,
buf[count] = '\0';
strim(buf);
- if (sscanf(buf, "[%d] = %u %d %d",
- &table_idx, &cpu_freq, &core_cap_level, &ms) != 4)
+ if (sscanf(buf, "[%d] = %u %d",
+ &table_idx, &cpu_freq, &core_cap_level) != 3)
return -1;
if ((table_idx < 0) || (table_idx >= ARRAY_SIZE(throttle_table)))
@@ -337,7 +217,6 @@ static ssize_t table_write(struct file *file,
/* round new settings before updating table */
throttle_table[table_idx].cpu_freq = clip_to_table(cpu_freq);
throttle_table[table_idx].core_cap_level = (core_cap_level / 50) * 50;
- throttle_table[table_idx].ms = jiffies_to_msecs(msecs_to_jiffies(ms));
return count;
}
@@ -353,10 +232,6 @@ static const struct file_operations table_fops = {
int __init tegra_throttle_debug_init(struct dentry *cpu_tegra_debugfs_root)
{
- if (!debugfs_create_file("throttle", 0644, cpu_tegra_debugfs_root,
- NULL, &throttle_fops))
- return -ENOMEM;
-
if (!debugfs_create_file("throttle_table", 0644, cpu_tegra_debugfs_root,
NULL, &table_fops))
return -ENOMEM;
diff --git a/arch/arm/mach-tegra/tegra_usb_modem_power.c b/arch/arm/mach-tegra/tegra_usb_modem_power.c
index db062ffac346..88543397f974 100644
--- a/arch/arm/mach-tegra/tegra_usb_modem_power.c
+++ b/arch/arm/mach-tegra/tegra_usb_modem_power.c
@@ -26,6 +26,9 @@
#include <linux/gpio.h>
#include <linux/usb.h>
#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
+#include <linux/slab.h>
#include <linux/wakelock.h>
#include <mach/tegra_usb_modem_power.h>
@@ -43,10 +46,11 @@ struct tegra_usb_modem {
struct delayed_work recovery_work; /* modem recovery work */
const struct tegra_modem_operations *ops; /* modem operations */
unsigned int capability; /* modem capability */
+ int system_suspend; /* system suspend flag */
+ struct notifier_block pm_notifier; /* pm event notifier */
+ struct notifier_block usb_notifier; /* usb event notifier */
};
-static struct tegra_usb_modem tegra_mdm;
-
/* supported modems */
static const struct usb_device_id modem_list[] = {
{USB_DEVICE(0x1983, 0x0310), /* Icera 450 rev1 */
@@ -55,6 +59,9 @@ static const struct usb_device_id modem_list[] = {
{USB_DEVICE(0x1983, 0x0321), /* Icera 450 rev2 */
.driver_info = TEGRA_MODEM_AUTOSUSPEND,
},
+ {USB_DEVICE(0x1983, 0x0327), /* Icera 450 5AE */
+ .driver_info = TEGRA_MODEM_AUTOSUSPEND,
+ },
{}
};
@@ -65,11 +72,14 @@ static irqreturn_t tegra_usb_modem_wake_thread(int irq, void *data)
wake_lock_timeout(&modem->wake_lock, HZ);
mutex_lock(&modem->lock);
if (modem->udev) {
- usb_lock_device(modem->udev);
pr_info("modem wake (%u)\n", ++(modem->wake_cnt));
- if (usb_autopm_get_interface(modem->intf) == 0)
- usb_autopm_put_interface_async(modem->intf);
- usb_unlock_device(modem->udev);
+
+ if (!modem->system_suspend) {
+ usb_lock_device(modem->udev);
+ if (usb_autopm_get_interface(modem->intf) == 0)
+ usb_autopm_put_interface_async(modem->intf);
+ usb_unlock_device(modem->udev);
+ }
}
mutex_unlock(&modem->lock);
@@ -89,7 +99,8 @@ static void tegra_usb_modem_recovery(struct work_struct *ws)
mutex_unlock(&modem->lock);
}
-static void device_add_handler(struct usb_device *udev)
+static void device_add_handler(struct tegra_usb_modem *modem,
+ struct usb_device *udev)
{
const struct usb_device_descriptor *desc = &udev->descriptor;
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
@@ -97,153 +108,222 @@ static void device_add_handler(struct usb_device *udev)
if (id) {
/* hold wakelock to ensure ril has enough time to restart */
- wake_lock_timeout(&tegra_mdm.wake_lock, HZ*10);
+ wake_lock_timeout(&modem->wake_lock, HZ * 10);
pr_info("Add device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
- mutex_lock(&tegra_mdm.lock);
- tegra_mdm.udev = udev;
- tegra_mdm.intf = intf;
- tegra_mdm.vid = desc->idVendor;
- tegra_mdm.pid = desc->idProduct;
- tegra_mdm.wake_cnt = 0;
- tegra_mdm.capability = id->driver_info;
- mutex_unlock(&tegra_mdm.lock);
+ mutex_lock(&modem->lock);
+ modem->udev = udev;
+ modem->intf = intf;
+ modem->vid = desc->idVendor;
+ modem->pid = desc->idProduct;
+ modem->wake_cnt = 0;
+ modem->capability = id->driver_info;
+ mutex_unlock(&modem->lock);
pr_info("persist_enabled: %u\n", udev->persist_enabled);
- if (tegra_mdm.capability & TEGRA_MODEM_AUTOSUSPEND) {
+#ifdef CONFIG_PM
+ if (modem->capability & TEGRA_MODEM_AUTOSUSPEND) {
+ pm_runtime_set_autosuspend_delay(&udev->dev, 2000);
usb_enable_autosuspend(udev);
pr_info("enable autosuspend for %s %s\n",
udev->manufacturer, udev->product);
}
+#endif
}
}
-static void device_remove_handler(struct usb_device *udev)
+static void device_remove_handler(struct tegra_usb_modem *modem,
+ struct usb_device *udev)
{
const struct usb_device_descriptor *desc = &udev->descriptor;
- if (desc->idVendor == tegra_mdm.vid &&
- desc->idProduct == tegra_mdm.pid) {
+ if (desc->idVendor == modem->vid &&
+ desc->idProduct == modem->pid) {
pr_info("Remove device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
- mutex_lock(&tegra_mdm.lock);
- tegra_mdm.udev = NULL;
- tegra_mdm.intf = NULL;
- tegra_mdm.vid = 0;
- mutex_unlock(&tegra_mdm.lock);
+ mutex_lock(&modem->lock);
+ modem->udev = NULL;
+ modem->intf = NULL;
+ modem->vid = 0;
+ mutex_unlock(&modem->lock);
- if (tegra_mdm.capability & TEGRA_MODEM_RECOVERY)
- queue_delayed_work(tegra_mdm.wq,
- &tegra_mdm.recovery_work, HZ * 10);
+ if (modem->capability & TEGRA_MODEM_RECOVERY)
+ queue_delayed_work(modem->wq,
+ &modem->recovery_work, HZ * 10);
}
}
-static int usb_notify(struct notifier_block *self, unsigned long action,
- void *blob)
+static int mdm_usb_notifier(struct notifier_block *notifier,
+ unsigned long usb_event,
+ void *udev)
{
- switch (action) {
+ struct tegra_usb_modem *modem =
+ container_of(notifier, struct tegra_usb_modem, usb_notifier);
+
+ switch (usb_event) {
case USB_DEVICE_ADD:
- device_add_handler(blob);
+ device_add_handler(modem, udev);
break;
case USB_DEVICE_REMOVE:
- device_remove_handler(blob);
+ device_remove_handler(modem, udev);
break;
}
-
return NOTIFY_OK;
}
-static struct notifier_block usb_nb = {
- .notifier_call = usb_notify,
-};
+static int mdm_pm_notifier(struct notifier_block *notifier,
+ unsigned long pm_event,
+ void *unused)
+{
+ struct tegra_usb_modem *modem =
+ container_of(notifier, struct tegra_usb_modem, pm_notifier);
-static int tegra_usb_modem_probe(struct platform_device *pdev)
+ mutex_lock(&modem->lock);
+ if (!modem->udev) {
+ mutex_unlock(&modem->lock);
+ return NOTIFY_DONE;
+ }
+
+ pr_info("%s: event %ld\n", __func__, pm_event);
+ switch (pm_event) {
+ case PM_SUSPEND_PREPARE:
+ if (wake_lock_active(&modem->wake_lock)) {
+ pr_warn("%s: wakelock was active, aborting suspend\n",
+ __func__);
+ return NOTIFY_STOP;
+ }
+
+ modem->system_suspend = 1;
+ mutex_unlock(&modem->lock);
+ return NOTIFY_OK;
+ case PM_POST_SUSPEND:
+ modem->system_suspend = 0;
+ mutex_unlock(&modem->lock);
+ return NOTIFY_OK;
+ }
+
+ mutex_unlock(&modem->lock);
+ return NOTIFY_DONE;
+}
+
+static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
{
struct tegra_usb_modem_power_platform_data *pdata =
pdev->dev.platform_data;
- int ret;
-
- if (!pdata) {
- dev_dbg(&pdev->dev, "platform_data not available\n");
- return -EINVAL;
- }
+ int ret = 0;
/* get modem operations from platform data */
- tegra_mdm.ops = (const struct tegra_modem_operations *)pdata->ops;
+ modem->ops = (const struct tegra_modem_operations *)pdata->ops;
- if (tegra_mdm.ops) {
+ if (modem->ops) {
/* modem init */
- if (tegra_mdm.ops->init) {
- ret = tegra_mdm.ops->init();
+ if (modem->ops->init) {
+ ret = modem->ops->init();
if (ret)
return ret;
}
/* start modem */
- if (tegra_mdm.ops->start)
- tegra_mdm.ops->start();
+ if (modem->ops->start)
+ modem->ops->start();
}
- mutex_init(&(tegra_mdm.lock));
- wake_lock_init(&(tegra_mdm.wake_lock), WAKE_LOCK_SUSPEND,
+ mutex_init(&(modem->lock));
+ wake_lock_init(&modem->wake_lock, WAKE_LOCK_SUSPEND,
"tegra_usb_mdm_lock");
- /* create work queue */
- tegra_mdm.wq = create_workqueue("tegra_usb_mdm_queue");
- INIT_DELAYED_WORK(&(tegra_mdm.recovery_work), tegra_usb_modem_recovery);
+ /* create work queue platform_driver_registe*/
+ modem->wq = create_workqueue("tegra_usb_mdm_queue");
+ INIT_DELAYED_WORK(&(modem->recovery_work), tegra_usb_modem_recovery);
/* create threaded irq for remote wakeup */
if (gpio_is_valid(pdata->wake_gpio)) {
/* get remote wakeup gpio from platform data */
- tegra_mdm.wake_gpio = pdata->wake_gpio;
+ modem->wake_gpio = pdata->wake_gpio;
- ret = gpio_request(tegra_mdm.wake_gpio, "usb_mdm_wake");
+ ret = gpio_request(modem->wake_gpio, "usb_mdm_wake");
if (ret)
return ret;
- tegra_gpio_enable(tegra_mdm.wake_gpio);
+ tegra_gpio_enable(modem->wake_gpio);
/* enable IRQ for remote wakeup */
- tegra_mdm.irq = gpio_to_irq(tegra_mdm.wake_gpio);
+ modem->irq = gpio_to_irq(modem->wake_gpio);
ret =
- request_threaded_irq(tegra_mdm.irq, NULL,
+ request_threaded_irq(modem->irq, NULL,
tegra_usb_modem_wake_thread,
pdata->flags, "tegra_usb_mdm_wake",
- &tegra_mdm);
+ modem);
if (ret < 0) {
dev_err(&pdev->dev, "%s: request_threaded_irq error\n",
__func__);
return ret;
}
- ret = enable_irq_wake(tegra_mdm.irq);
+ ret = enable_irq_wake(modem->irq);
if (ret) {
dev_err(&pdev->dev, "%s: enable_irq_wake error\n",
__func__);
- free_irq(tegra_mdm.irq, &tegra_mdm);
+ free_irq(modem->irq, modem);
return ret;
}
}
- usb_register_notify(&usb_nb);
- dev_info(&pdev->dev, "Initialized tegra_usb_modem_power\n");
+ modem->pm_notifier.notifier_call = mdm_pm_notifier;
+ modem->usb_notifier.notifier_call = mdm_usb_notifier;
- return 0;
+ usb_register_notify(&modem->usb_notifier);
+ register_pm_notifier(&modem->pm_notifier);
+
+ return ret;
+}
+
+static int tegra_usb_modem_probe(struct platform_device *pdev)
+{
+ struct tegra_usb_modem_power_platform_data *pdata =
+ pdev->dev.platform_data;
+ struct tegra_usb_modem *modem;
+ int ret = 0;
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "platform_data not available\n");
+ return -EINVAL;
+ }
+
+ modem = kzalloc(sizeof(struct tegra_usb_modem), GFP_KERNEL);
+ if (!modem) {
+ dev_dbg(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ ret = mdm_init(modem, pdev);
+ if (ret) {
+ kfree(modem);
+ return ret;
+ }
+
+ dev_set_drvdata(&pdev->dev, modem);
+
+ return ret;
}
static int __exit tegra_usb_modem_remove(struct platform_device *pdev)
{
- usb_unregister_notify(&usb_nb);
+ struct tegra_usb_modem *modem = platform_get_drvdata(pdev);
- if (tegra_mdm.irq) {
- disable_irq_wake(tegra_mdm.irq);
- free_irq(tegra_mdm.irq, &tegra_mdm);
+ unregister_pm_notifier(&modem->pm_notifier);
+ usb_unregister_notify(&modem->usb_notifier);
+
+ if (modem->irq) {
+ disable_irq_wake(modem->irq);
+ free_irq(modem->irq, modem);
}
+ kfree(modem);
return 0;
}
@@ -251,17 +331,21 @@ static int __exit tegra_usb_modem_remove(struct platform_device *pdev)
static int tegra_usb_modem_suspend(struct platform_device *pdev,
pm_message_t state)
{
+ struct tegra_usb_modem *modem = platform_get_drvdata(pdev);
+
/* send L3 hint to modem */
- if (tegra_mdm.ops && tegra_mdm.ops->suspend)
- tegra_mdm.ops->suspend();
+ if (modem->ops && modem->ops->suspend)
+ modem->ops->suspend();
return 0;
}
static int tegra_usb_modem_resume(struct platform_device *pdev)
{
+ struct tegra_usb_modem *modem = platform_get_drvdata(pdev);
+
/* send L3->L0 hint to modem */
- if (tegra_mdm.ops && tegra_mdm.ops->resume)
- tegra_mdm.ops->resume();
+ if (modem->ops && modem->ops->resume)
+ modem->ops->resume();
return 0;
}
#endif
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index e1cfccea6e39..8c36159e085a 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -859,7 +859,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
val |= HOSTPC1_DEVLC_PHCD;
writel(val, base + HOSTPC1_DEVLC);
#endif
- if (phy->instance == 2) {
+ if (phy->hotplug) {
val = readl(base + USB_SUSP_CTRL);
val |= USB_PHY_CLK_VALID_INT_ENB;
writel(val, base + USB_SUSP_CTRL);
@@ -1667,8 +1667,11 @@ static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
{
unsigned long val;
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
void __iomem *base = phy->regs;
+#else
void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+#endif
unsigned int inst = phy->instance;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
@@ -1723,7 +1726,7 @@ static int uhsic_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
return 0;
}
-static int uhsic_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
+static int usb_phy_set_tx_fill_tuning(struct tegra_usb_phy *phy, bool is_dpd)
{
unsigned long val;
void __iomem *base = phy->regs;
@@ -2401,11 +2404,7 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
writel(val, base + HOSTPC1_DEVLC);
#endif
- val = readl(base + USB_TXFILLTUNING);
- if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
- val = USB_FIFO_TXFILL_THRES(0x10);
- writel(val, base + USB_TXFILLTUNING);
- }
+ usb_phy_set_tx_fill_tuning(phy, is_dpd);
val = readl(base + USB_PORTSC1);
val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
@@ -2497,7 +2496,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
int i;
int err;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- struct tegra_ulpi_config *uhsic_config;
+ struct tegra_uhsic_config *uhsic_config;
int reset_gpio, enable_gpio;
#endif
@@ -2763,11 +2762,14 @@ void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
utmi_phy_postresume,
NULL,
NULL,
- uhsic_phy_postresume,
+ NULL,
};
- if (postresume[phy->usb_phy_type])
- postresume[phy->usb_phy_type](phy, is_dpd);
+ usb_phy_set_tx_fill_tuning(phy, is_dpd);
+
+ // If Phy type is utmi, call its post resume
+ if (phy->usb_phy_type == 0)
+ utmi_phy_postresume(phy, is_dpd);
}
void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd)
diff --git a/arch/arm/mach-tegra/wdt-recovery.c b/arch/arm/mach-tegra/wdt-recovery.c
index 537b1c0db853..f5a18bb9cb6f 100644
--- a/arch/arm/mach-tegra/wdt-recovery.c
+++ b/arch/arm/mach-tegra/wdt-recovery.c
@@ -30,7 +30,7 @@
#include <asm/mach/time.h>
#include <asm/localtimer.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/clk.h>
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 0dddb54ea986..e6871a3e4d1c 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -335,6 +335,8 @@ static void __init l2x0_unlock(__u32 cache_id)
int lockregs;
int i;
+ cache_id &= L2X0_CACHE_ID_PART_MASK;
+
if (cache_id == L2X0_CACHE_ID_PART_L310)
lockregs = 8;
else
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 88fb3d9e0640..2e6849b41f66 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -379,26 +379,31 @@ ENTRY(cpu_arm920_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
.globl cpu_arm920_suspend_size
-.equ cpu_arm920_suspend_size, 4 * 3
+.equ cpu_arm920_suspend_size, 4 * 4
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_arm920_do_suspend)
- stmfd sp!, {r4 - r6, lr}
+ stmfd sp!, {r4 - r7, lr}
mrc p15, 0, r4, c13, c0, 0 @ PID
mrc p15, 0, r5, c3, c0, 0 @ Domain ID
- mrc p15, 0, r6, c1, c0, 0 @ Control register
- stmia r0, {r4 - r6}
- ldmfd sp!, {r4 - r6, pc}
+ mrc p15, 0, r6, c2, c0, 0 @ TTB address
+ mrc p15, 0, r7, c1, c0, 0 @ Control register
+ stmia r0, {r4 - r7}
+ ldmfd sp!, {r4 - r7, pc}
ENDPROC(cpu_arm920_do_suspend)
ENTRY(cpu_arm920_do_resume)
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs
mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches
- ldmia r0, {r4 - r6}
+ ldmia r0, {r4 - r7}
mcr p15, 0, r4, c13, c0, 0 @ PID
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
- mcr p15, 0, r1, c2, c0, 0 @ TTB address
- mov r0, r6 @ control register
+ mcr p15, 0, r6, c2, c0, 0 @ TTB address
+ mov r0, r7 @ control register
+ mov r2, r6, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
b cpu_resume_mmu
ENDPROC(cpu_arm920_do_resume)
#endif
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 9f8fd91f918a..cd8f79c3a282 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -394,26 +394,31 @@ ENTRY(cpu_arm926_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
.globl cpu_arm926_suspend_size
-.equ cpu_arm926_suspend_size, 4 * 3
+.equ cpu_arm926_suspend_size, 4 * 4
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_arm926_do_suspend)
- stmfd sp!, {r4 - r6, lr}
+ stmfd sp!, {r4 - r7, lr}
mrc p15, 0, r4, c13, c0, 0 @ PID
mrc p15, 0, r5, c3, c0, 0 @ Domain ID
- mrc p15, 0, r6, c1, c0, 0 @ Control register
- stmia r0, {r4 - r6}
- ldmfd sp!, {r4 - r6, pc}
+ mrc p15, 0, r6, c2, c0, 0 @ TTB address
+ mrc p15, 0, r7, c1, c0, 0 @ Control register
+ stmia r0, {r4 - r7}
+ ldmfd sp!, {r4 - r7, pc}
ENDPROC(cpu_arm926_do_suspend)
ENTRY(cpu_arm926_do_resume)
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs
mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches
- ldmia r0, {r4 - r6}
+ ldmia r0, {r4 - r7}
mcr p15, 0, r4, c13, c0, 0 @ PID
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
- mcr p15, 0, r1, c2, c0, 0 @ TTB address
- mov r0, r6 @ control register
+ mcr p15, 0, r6, c2, c0, 0 @ TTB address
+ mov r0, r7 @ control register
+ mov r2, r6, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
b cpu_resume_mmu
ENDPROC(cpu_arm926_do_resume)
#endif
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 7d91545d089b..69e7f2ef7384 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -168,19 +168,20 @@ ENTRY(cpu_sa1100_set_pte_ext)
mov pc, lr
.globl cpu_sa1100_suspend_size
-.equ cpu_sa1100_suspend_size, 4 * 3
+.equ cpu_sa1100_suspend_size, 4*4
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_sa1100_do_suspend)
- stmfd sp!, {r4 - r6, lr}
+ stmfd sp!, {r4 - r7, lr}
mrc p15, 0, r4, c3, c0, 0 @ domain ID
- mrc p15, 0, r5, c13, c0, 0 @ PID
- mrc p15, 0, r6, c1, c0, 0 @ control reg
- stmia r0, {r4 - r6} @ store cp regs
- ldmfd sp!, {r4 - r6, pc}
+ mrc p15, 0, r5, c2, c0, 0 @ translation table base addr
+ mrc p15, 0, r6, c13, c0, 0 @ PID
+ mrc p15, 0, r7, c1, c0, 0 @ control reg
+ stmia r0, {r4 - r7} @ store cp regs
+ ldmfd sp!, {r4 - r7, pc}
ENDPROC(cpu_sa1100_do_suspend)
ENTRY(cpu_sa1100_do_resume)
- ldmia r0, {r4 - r6} @ load cp regs
+ ldmia r0, {r4 - r7} @ load cp regs
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ flush I+D TLBs
mcr p15, 0, ip, c7, c7, 0 @ flush I&D cache
@@ -188,9 +189,13 @@ ENTRY(cpu_sa1100_do_resume)
mcr p15, 0, ip, c9, c0, 5 @ allow user space to use RB
mcr p15, 0, r4, c3, c0, 0 @ domain ID
- mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r5, c13, c0, 0 @ PID
- mov r0, r6 @ control register
+ mcr p15, 0, r5, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r6, c13, c0, 0 @ PID
+ mov r0, r7 @ control register
+ mov r2, r5, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
b cpu_resume_mmu
ENDPROC(cpu_sa1100_do_resume)
#endif
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index d061d2fa5506..a923aa0fd00d 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -128,18 +128,20 @@ ENTRY(cpu_v6_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
.globl cpu_v6_suspend_size
-.equ cpu_v6_suspend_size, 4 * 6
+.equ cpu_v6_suspend_size, 4 * 8
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_v6_do_suspend)
- stmfd sp!, {r4 - r9, lr}
+ stmfd sp!, {r4 - r11, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mrc p15, 0, r5, c3, c0, 0 @ Domain ID
- mrc p15, 0, r6, c2, c0, 1 @ Translation table base 1
- mrc p15, 0, r7, c1, c0, 1 @ auxiliary control register
- mrc p15, 0, r8, c1, c0, 2 @ co-processor access control
- mrc p15, 0, r9, c1, c0, 0 @ control register
- stmia r0, {r4 - r9}
- ldmfd sp!, {r4- r9, pc}
+ mrc p15, 0, r5, c13, c0, 1 @ Context ID
+ mrc p15, 0, r6, c3, c0, 0 @ Domain ID
+ mrc p15, 0, r7, c2, c0, 0 @ Translation table base 0
+ mrc p15, 0, r8, c2, c0, 1 @ Translation table base 1
+ mrc p15, 0, r9, c1, c0, 1 @ auxiliary control register
+ mrc p15, 0, r10, c1, c0, 2 @ co-processor access control
+ mrc p15, 0, r11, c1, c0, 0 @ control register
+ stmia r0, {r4 - r11}
+ ldmfd sp!, {r4- r11, pc}
ENDPROC(cpu_v6_do_suspend)
ENTRY(cpu_v6_do_resume)
@@ -148,21 +150,25 @@ ENTRY(cpu_v6_do_resume)
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcr p15, 0, ip, c7, c15, 0 @ clean+invalidate cache
mcr p15, 0, ip, c7, c10, 4 @ drain write buffer
- mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
- ldmia r0, {r4 - r9}
+ ldmia r0, {r4 - r11}
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mcr p15, 0, r5, c3, c0, 0 @ Domain ID
- ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
- ALT_UP(orr r1, r1, #TTB_FLAGS_UP)
- mcr p15, 0, r1, c2, c0, 0 @ Translation table base 0
- mcr p15, 0, r6, c2, c0, 1 @ Translation table base 1
- mcr p15, 0, r7, c1, c0, 1 @ auxiliary control register
- mcr p15, 0, r8, c1, c0, 2 @ co-processor access control
+ mcr p15, 0, r5, c13, c0, 1 @ Context ID
+ mcr p15, 0, r6, c3, c0, 0 @ Domain ID
+ mcr p15, 0, r7, c2, c0, 0 @ Translation table base 0
+ mcr p15, 0, r8, c2, c0, 1 @ Translation table base 1
+ mcr p15, 0, r9, c1, c0, 1 @ auxiliary control register
+ mcr p15, 0, r10, c1, c0, 2 @ co-processor access control
mcr p15, 0, ip, c2, c0, 2 @ TTB control register
mcr p15, 0, ip, c7, c5, 4 @ ISB
- mov r0, r9 @ control register
+ mov r0, r11 @ control register
+ mov r2, r7, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, cpu_resume_l1_flags
b cpu_resume_mmu
ENDPROC(cpu_v6_do_resume)
+cpu_resume_l1_flags:
+ ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
+ ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
#endif
string cpu_v6_name, "ARMv6-compatible processor"
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index bd0f3a18ab41..a502958a71f8 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -260,17 +260,19 @@ ENDPROC(cpu_v7_set_pte_ext)
.equ cpu_v7_suspend_size, (4 * 10) + cpu_v7_debug_suspend_size
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_v7_do_suspend)
- stmfd sp!, {r0, r3 - r10, lr}
+ stmfd sp!, {r0, r3 - r11, lr}
mrc p15, 0, r3, c15, c0, 1 @ diag
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID
- stmia r0!, {r3 - r5}
+ mrc p15, 0, r5, c13, c0, 1 @ Context ID
+ mrc p15, 0, r6, c13, c0, 3 @ User r/o thread ID
+ stmia r0!, {r3 - r6}
mrc p15, 0, r6, c3, c0, 0 @ Domain ID
- mrc p15, 0, r7, c2, c0, 1 @ TTB 1
- mrc p15, 0, r8, c1, c0, 0 @ Control register
- mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register
- mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control
- stmia r0!, {r6 - r10}
+ mrc p15, 0, r7, c2, c0, 0 @ TTB 0
+ mrc p15, 0, r8, c2, c0, 1 @ TTB 1
+ mrc p15, 0, r9, c1, c0, 0 @ Control register
+ mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register
+ mrc p15, 0, r11, c1, c0, 2 @ Co-processor access control
+ stmia r0!, {r6 - r11}
#ifdef CONFIG_ARM_SAVE_DEBUG_CONTEXT
/* Save CP14 debug controller context */
@@ -295,7 +297,7 @@ ENTRY(cpu_v7_do_suspend)
mrc p14, 0, r8, c0, c0, 0 @ read IDR
mov r3, r8, lsr #24
- and r3, r3, #0xf @ r3 has the number of brkpt
+ and r3, r3, #0xf @ r3 has the number of brkpt
rsb r3, r3, #0xf
/* r3 = (15 - #of brkpt) ;
@@ -322,7 +324,7 @@ ENTRY(cpu_v7_do_suspend)
save_brkpt c1
save_brkpt c0
- mov r3, r8, lsr #28 @ r3 has the number of wpt
+ mov r3, r8, lsr #28 @ r3 has the number of wpt
rsb r3, r3, #0xf
/* r3 = (15 - #of wpt) ;
@@ -349,31 +351,29 @@ ENTRY(cpu_v7_do_suspend)
save_wpt c1
save_wpt c0
#endif
- ldmfd sp!, {r0, r3 - r10, pc}
+ ldmfd sp!, {r0, r3 - r11, pc}
ENDPROC(cpu_v7_do_suspend)
ENTRY(cpu_v7_do_resume)
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
- mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
- ldmia r0!, {r3 - r5}
+ ldmia r0!, {r3 - r6}
#ifndef CONFIG_TRUSTED_FOUNDATIONS
mcr p15, 0, r3, c15, c0, 1 @ diag
#endif
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mcr p15, 0, r5, c13, c0, 3 @ User r/o thread ID
- ldmia r0!, {r6 - r10}
+ mcr p15, 0, r5, c13, c0, 1 @ Context ID
+ mcr p15, 0, r6, c13, c0, 3 @ User r/o thread ID
+ ldmia r0!, {r6 - r11}
mcr p15, 0, r6, c3, c0, 0 @ Domain ID
- ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
- ALT_UP(orr r1, r1, #TTB_FLAGS_UP)
- mcr p15, 0, r1, c2, c0, 0 @ TTB 0
- mcr p15, 0, r7, c2, c0, 1 @ TTB 1
+ mcr p15, 0, r7, c2, c0, 0 @ TTB 0
+ mcr p15, 0, r8, c2, c0, 1 @ TTB 1
mcr p15, 0, ip, c2, c0, 2 @ TTB control register
mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
- teq r4, r9 @ Is it already set?
- mcrne p15, 0, r9, c1, c0, 1 @ No, so write it
- mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control
+ teq r4, r10 @ Is it already set?
+ mcrne p15, 0, r10, c1, c0, 1 @ No, so write it
+ mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control
ldr r4, =PRRR @ PRRR
ldr r5, =NMRR @ NMRR
mcr p15, 0, r4, c10, c2, 0 @ write PRRR
@@ -382,6 +382,7 @@ ENTRY(cpu_v7_do_resume)
#ifdef CONFIG_ARM_SAVE_DEBUG_CONTEXT
/* Restore CP14 debug controller context */
+
ldmia r0!, {r2 - r5}
mcr p14, 0, r3, c0, c6, 0 @ DBGWFAR
mcr p14, 0, r4, c0, c7, 0 @ DBGVCR
@@ -399,15 +400,14 @@ ENTRY(cpu_v7_do_resume)
ldrne r4, [r0], #4
mcrne p14, 0, r4, c0, c0, 2 @ DBGDTRRXext
- mrc p14, 0, r6, c0, c0, 0 @ read IDR
- mov r3, r6, lsr #24
- and r3, r3, #0xf @ r3 has the number of brkpt
+ mrc p14, 0, r8, c0, c0, 0 @ read IDR
+ mov r3, r8, lsr #24
+ and r3, r3, #0xf @ r3 has the number of brkpt
rsb r3, r3, #0xf
- /*
- * r3 = (15 - # of wpt) ;
- * switch offset = r3*12 - 4 = (r3*3 - 1)<<2
- */
+ /* r3 = (15 - #of wpt) ;
+ switch offset = r3*12 - 4 = (r3*3 - 1)<<2
+ */
add r3, r3, r3, lsl #1
sub r3, r3, #1
add pc, pc, r3, lsl #2
@@ -429,7 +429,7 @@ ENTRY(cpu_v7_do_resume)
restore_brkpt c1
restore_brkpt c0
- mov r3, r6, lsr #28 @ r3 has the number of wpt
+ mov r3, r8, lsr #28 @ r3 has the number of wpt
rsb r3, r3, #0xf
/* r3 = (15 - #of wpt) ;
@@ -462,9 +462,15 @@ start_restore_wpt:
isb
#endif
dsb
- mov r0, r8 @ Control Register
+ mov r0, r9 @ control register
+ mov r2, r7, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, cpu_resume_l1_flags
b cpu_resume_mmu
ENDPROC(cpu_v7_do_resume)
+cpu_resume_l1_flags:
+ ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
+ ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
#endif
__CPUINIT
@@ -545,6 +551,12 @@ __v7_setup:
mrcge p15, 0, r10, c15, c0, 0 @ read power control register
orrge r10, r10, #1 @ enable dynamic clock gating
mcrge p15, 0, r10, c15, c0, 0 @ write power control register
+#ifdef CONFIG_ARM_ERRATA_716044
+ cmp r6, #0x12 @ present in r1p0 - r1p2
+ mrcle p15, 0, r10, c1, c0, 0
+ orrle r10, r10, #(1 << 14) @ set SCTLR.RR
+ mcrle p15, 0, r10, c1, c0, 0
+#endif
#ifdef CONFIG_ARM_ERRATA_720791
teq r5, #0x00100000 @ only present in r1p*
mrceq p15, 0, r10, c15, c0, 2 @ read "chicken power ctrl" reg
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 5ae0db4f44bd..1a2021cedc76 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -406,23 +406,24 @@ ENTRY(cpu_xsc3_set_pte_ext)
.align
.globl cpu_xsc3_suspend_size
-.equ cpu_xsc3_suspend_size, 4 * 6
+.equ cpu_xsc3_suspend_size, 4 * 7
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_xsc3_do_suspend)
- stmfd sp!, {r4 - r9, lr}
+ stmfd sp!, {r4 - r10, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
mrc p15, 0, r5, c15, c1, 0 @ CP access reg
mrc p15, 0, r6, c13, c0, 0 @ PID
mrc p15, 0, r7, c3, c0, 0 @ domain ID
- mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg
- mrc p15, 0, r9, c1, c0, 0 @ control reg
+ mrc p15, 0, r8, c2, c0, 0 @ translation table base addr
+ mrc p15, 0, r9, c1, c0, 1 @ auxiliary control reg
+ mrc p15, 0, r10, c1, c0, 0 @ control reg
bic r4, r4, #2 @ clear frequency change bit
- stmia r0, {r4 - r9} @ store cp regs
- ldmia sp!, {r4 - r9, pc}
+ stmia r0, {r4 - r10} @ store cp regs
+ ldmia sp!, {r4 - r10, pc}
ENDPROC(cpu_xsc3_do_suspend)
ENTRY(cpu_xsc3_do_resume)
- ldmia r0, {r4 - r9} @ load cp regs
+ ldmia r0, {r4 - r10} @ load cp regs
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer
@@ -432,10 +433,15 @@ ENTRY(cpu_xsc3_do_resume)
mcr p15, 0, r5, c15, c1, 0 @ CP access reg
mcr p15, 0, r6, c13, c0, 0 @ PID
mcr p15, 0, r7, c3, c0, 0 @ domain ID
- orr r1, r1, #0x18 @ cache the page table in L2
- mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg
- mov r0, r9 @ control register
+ mcr p15, 0, r8, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r9, c1, c0, 1 @ auxiliary control reg
+
+ @ temporarily map resume_turn_on_mmu into the page table,
+ @ otherwise prefetch abort occurs after MMU is turned on
+ mov r0, r10 @ control register
+ mov r2, r8, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, =0x542e @ section flags
b cpu_resume_mmu
ENDPROC(cpu_xsc3_do_resume)
#endif
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 2b4152508d73..b0fe4b1e233d 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -520,23 +520,24 @@ ENTRY(cpu_xscale_set_pte_ext)
.align
.globl cpu_xscale_suspend_size
-.equ cpu_xscale_suspend_size, 4 * 6
+.equ cpu_xscale_suspend_size, 4 * 7
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_xscale_do_suspend)
- stmfd sp!, {r4 - r9, lr}
+ stmfd sp!, {r4 - r10, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
mrc p15, 0, r5, c15, c1, 0 @ CP access reg
mrc p15, 0, r6, c13, c0, 0 @ PID
mrc p15, 0, r7, c3, c0, 0 @ domain ID
- mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg
- mrc p15, 0, r9, c1, c0, 0 @ control reg
+ mrc p15, 0, r8, c2, c0, 0 @ translation table base addr
+ mrc p15, 0, r9, c1, c1, 0 @ auxiliary control reg
+ mrc p15, 0, r10, c1, c0, 0 @ control reg
bic r4, r4, #2 @ clear frequency change bit
- stmia r0, {r4 - r9} @ store cp regs
- ldmfd sp!, {r4 - r9, pc}
+ stmia r0, {r4 - r10} @ store cp regs
+ ldmfd sp!, {r4 - r10, pc}
ENDPROC(cpu_xscale_do_suspend)
ENTRY(cpu_xscale_do_resume)
- ldmia r0, {r4 - r9} @ load cp regs
+ ldmia r0, {r4 - r10} @ load cp regs
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
@@ -544,9 +545,13 @@ ENTRY(cpu_xscale_do_resume)
mcr p15, 0, r5, c15, c1, 0 @ CP access reg
mcr p15, 0, r6, c13, c0, 0 @ PID
mcr p15, 0, r7, c3, c0, 0 @ domain ID
- mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg
- mov r0, r9 @ control register
+ mcr p15, 0, r8, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r9, c1, c1, 0 @ auxiliary control reg
+ mov r0, r10 @ control register
+ mov r2, r8, lsr #14 @ get TTB0 base
+ mov r2, r2, lsl #14
+ ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
b cpu_resume_mmu
ENDPROC(cpu_xscale_do_resume)
#endif
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 4e0a371630b3..485e58bf7f49 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -58,6 +58,13 @@ static int report_trace(struct stackframe *frame, void *d)
return *depth == 0;
}
+#ifdef CONFIG_ANDROID
+/* Android has a different stack frame than Linux */
+struct frame_tail {
+ unsigned long fp;
+ unsigned long lr;
+} __attribute__((packed));
+#else
/*
* The registers we're interested in are at the end of the variable
* length saved register structure. The fp points at the end of this
@@ -69,6 +76,7 @@ struct frame_tail {
unsigned long sp;
unsigned long lr;
} __attribute__((packed));
+#endif
static struct frame_tail* user_backtrace(struct frame_tail *tail)
{
@@ -84,15 +92,29 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail)
/* frame pointers should strictly progress back up the stack
* (towards higher addresses) */
+#ifdef CONFIG_ANDROID
+ if (tail >= (struct frame_tail *) buftail[0].fp)
+#else
if (tail + 1 >= buftail[0].fp)
+#endif
return NULL;
+#ifdef CONFIG_ANDROID
+ /* Android has a different stack frame than Linux */
+ return (struct frame_tail *) (buftail[0].fp - sizeof(unsigned long));
+#else
return buftail[0].fp-1;
+#endif
}
static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
{
+#ifdef CONFIG_ANDROID
+ struct frame_tail *tail = (struct frame_tail *)
+ (regs->ARM_fp - sizeof(unsigned long));
+#else
struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+#endif
if (!user_mode(regs)) {
struct stackframe frame;
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index e381dc68505d..462a94d2a2c1 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/cpu.h>
+#include <linux/hardirq.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/signal.h>
@@ -425,7 +426,10 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
static void vfp_enable(void *unused)
{
- u32 access = get_copro_access();
+ u32 access;
+
+ BUG_ON(preemptible());
+ access = get_copro_access();
/*
* Enable full access to VFP (cp10 and cp11)
@@ -575,7 +579,7 @@ static int __init vfp_init(void)
unsigned int cpu_arch = cpu_architecture();
if (cpu_arch >= CPU_ARCH_ARMv6)
- vfp_enable(NULL);
+ on_each_cpu(vfp_enable, NULL, 1);
/*
* First check that there is a VFP that we can use.
@@ -596,8 +600,6 @@ static int __init vfp_init(void)
} else {
hotcpu_notifier(vfp_hotplug, 0);
- smp_call_function(vfp_enable, NULL, 1);
-
VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
printk("implementor %02x architecture %d part %02x variant %x rev %x\n",
(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 0f6c7fb418e8..9ef0a5326f17 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 defd57963c84..5e75d1b683e2 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 abd76678ed73..d92e9b1cb83c 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 b7d16143edeb..9b36703025cc 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 32620c4f1683..be7b068afaac 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 86cc34251ac5..bb9701da79bd 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 b3b4b8f7f409..34038030f655 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 9a3a8c564389..5f6b2478bf17 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 428836fc5835..cc7b4f764d63 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 000000000000..febd6de6c8ac
--- /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 7c0c35a39c33..ffa46a92ad33 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 a239ce8e1f0f..1eb6de3ac479 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 d86fd261e676..2ab532410c72 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 6db161f64ae0..a9a113782821 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 3acc42805e21..629806dc5cbf 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 22a96ed343eb..291cb4be5c39 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 3a0893f9cdc3..17e9c1cfdf4e 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 2252079279e8..e929ec84fc53 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 5cd25bd907f8..81c054e866df 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 b46603386006..28597ef4cc98 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 a4c1e0d82939..96916bed997f 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 6a269df4ff35..def8a2083d98 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 0ec980d7db07..4328d49ddcbf 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 41f72657f829..71c98bc48453 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 c33557ce5a67..618f1bf52780 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 f4d859fca7fe..bf33c0302257 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 404d771a717e..f5aea996e2d6 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 5d404e44fd20..08b81e261611 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 19d35bca5b0b..adfda3e712dc 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 129825cd5f83..f3b56bbf847e 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 074a42f125be..fc965e4f5b53 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 17c8b8535a62..1e8219943b4a 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 4627c514622a..012f50b7a5f4 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 2efd283b32b5..8a72cd7aae89 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 a2e02369d8e3..5e8eaa123124 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 000000000000..b20c036bb06c
--- /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 000000000000..94cf1da31ec2
--- /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 3adb46a3bb80..3e2d23ab3374 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 655d07c736a8..378d46fabedf 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 7db14fcf2573..f41b44ce9530 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 7f2c13614660..e0022166fff6 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 e90b130bcd65..de0c662ba613 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 ff47cb123d0d..46728c331f83 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 ba85a0091642..f8964cb92965 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 e8ea75c424c6..94ba777bcdb3 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 a077326f2553..cf56768e2baa 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 8931c8a673e5..d58757fc532a 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 d5ed6a22ddac..d767ea05d6eb 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 ed62a52eca03..34ec9c16aac2 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 ebb4afe6c702..3875c21e04fa 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 2bd93d7a5170..bd5427d1f9e3 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 440b97d9e44b..86817085aec7 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 2a288e936a84..c5338cd45aa7 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 330b968393d6..28bed97ae1a5 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 4dfe8176308c..8fec147471a8 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 c6822c39541c..495586924d60 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 c00833de19da..bf48767e0ef2 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 34f83a4c9561..dc44c5c33e01 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 d298e7bd26d2..def9c54f73f5 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 b455fd5e1c00..cc80a0bb3e86 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 4fba62acf757..aa826d90f00d 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 fc5f13d47ad9..47eac7b92372 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 35b696966479..1b3b89b3c274 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 f1d88c571bc4..802bbd6c2b8e 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 8ceae0a8ba0f..3731f0ee3084 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 4c3461a67f4a..427cd9911569 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 918e59fb4953..85e93f7a56c3 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 daa7d2605aaf..04affb50b18b 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 000000000000..d823c85166c8
--- /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 000000000000..3ef70380dd82
--- /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 000000000000..a341e1547099
--- /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 000000000000..fdc0d993e381
--- /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 000000000000..3a38979a8dd2
--- /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 000000000000..cfa7fb915b39
--- /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 000000000000..5e78748e4a3b
--- /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);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares 11n cfg command
+ *
+ * @param pmpriv 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_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_11N_CFG *htcfg = &cmd->params.htcfg;
+ mlan_ds_11n_tx_cfg *txcfg = (mlan_ds_11n_tx_cfg *) pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_CFG) + S_DS_GEN);
+ htcfg->action = wlan_cpu_to_le16(cmd_action);
+ htcfg->ht_tx_cap = wlan_cpu_to_le16(txcfg->httxcap);
+ htcfg->ht_tx_info = wlan_cpu_to_le16(txcfg->httxinfo);
+ htcfg->misc_config = wlan_cpu_to_le16(txcfg->misc_cfg);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of 11ncfg
+ *
+ * @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_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_11N_CFG *htcfg = &resp->params.htcfg;
+
+ ENTER();
+ if (pioctl_buf && (wlan_le16_to_cpu(htcfg->action) == HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ cfg->param.tx_cfg.httxcap = wlan_le16_to_cpu(htcfg->ht_tx_cap);
+ cfg->param.tx_cfg.httxinfo = wlan_le16_to_cpu(htcfg->ht_tx_info);
+ cfg->param.tx_cfg.misc_cfg = wlan_le16_to_cpu(htcfg->misc_config);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares TX BF configuration command
+ *
+ * @param pmpriv 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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TX_BF_CFG *txbfcfg = &cmd->params.tx_bf_cfg;
+ mlan_ds_11n_tx_bf_cfg *txbf = (mlan_ds_11n_tx_bf_cfg *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_BF_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TX_BF_CFG) + S_DS_GEN);
+
+ if (txbf->bf_action == SET_GET_BF_PERIODICITY) {
+ memcpy(pmadapter, txbfcfg->body.bf_periodicity.peer_mac,
+ txbf->body.bf_periodicity[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ }
+ txbfcfg->action = wlan_cpu_to_le16(txbf->action);
+ txbfcfg->bf_action = wlan_cpu_to_le16(txbf->bf_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ switch (txbf->bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ txbfcfg->body.bf_global_cfg.bf_enbl =
+ txbf->body.bf_global_cfg.bf_enbl;
+ txbfcfg->body.bf_global_cfg.sounding_enbl =
+ txbf->body.bf_global_cfg.sounding_enbl;
+ txbfcfg->body.bf_global_cfg.fb_type =
+ txbf->body.bf_global_cfg.fb_type;
+ txbfcfg->body.bf_global_cfg.snr_threshold =
+ txbf->body.bf_global_cfg.snr_threshold;
+ txbfcfg->body.bf_global_cfg.sounding_interval =
+ wlan_cpu_to_le16(txbf->body.bf_global_cfg.sounding_interval);
+ txbfcfg->body.bf_global_cfg.bf_mode =
+ txbf->body.bf_global_cfg.bf_mode;
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ memcpy(pmadapter, txbfcfg->body.bf_sound_args.peer_mac,
+ txbf->body.bf_sound[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ txbfcfg->body.bf_periodicity.interval =
+ wlan_cpu_to_le16(txbf->body.bf_periodicity->interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ memcpy(pmadapter, txbfcfg->body.tx_bf_peer.peer_mac,
+ txbf->body.tx_bf_peer[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbfcfg->body.tx_bf_peer.bf_enbl = txbf->body.tx_bf_peer[0].bf_enbl;
+ txbfcfg->body.tx_bf_peer.sounding_enbl =
+ txbf->body.tx_bf_peer[0].sounding_enbl;
+ txbfcfg->body.tx_bf_peer.fb_type = txbf->body.tx_bf_peer[0].fb_type;
+ break;
+ case SET_SNR_THR_PEER:
+ memcpy(pmadapter, txbfcfg->body.bf_snr.peer_mac,
+ txbf->body.bf_snr[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbfcfg->body.bf_snr.snr = txbf->body.bf_snr[0].snr;
+ break;
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response
+ * of TX BF configuration
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TX_BF_CFG *txbfcfg = &resp->params.tx_bf_cfg;
+ mlan_ds_11n_cfg *cfg_11n = MNULL;
+ mlan_ds_11n_tx_bf_cfg *txbf = MNULL;
+ bf_peer_args *tx_bf_peer;
+ bf_snr_thr_t *bf_snr;
+ int i;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg_11n = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ txbf = (mlan_ds_11n_tx_bf_cfg *) & cfg_11n->param.tx_bf;
+ txbf->bf_action = wlan_le16_to_cpu(txbfcfg->bf_action);
+ switch (txbf->bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ txbf->body.bf_global_cfg.bf_enbl =
+ txbfcfg->body.bf_global_cfg.bf_enbl;
+ txbf->body.bf_global_cfg.sounding_enbl =
+ txbfcfg->body.bf_global_cfg.sounding_enbl;
+ txbf->body.bf_global_cfg.fb_type =
+ txbfcfg->body.bf_global_cfg.fb_type;
+ txbf->body.bf_global_cfg.snr_threshold =
+ txbfcfg->body.bf_global_cfg.snr_threshold;
+ txbf->body.bf_global_cfg.sounding_interval =
+ wlan_le16_to_cpu(txbfcfg->body.bf_global_cfg.sounding_interval);
+ txbf->body.bf_global_cfg.bf_mode =
+ txbfcfg->body.bf_global_cfg.bf_mode;
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ memcpy(pmadapter, txbf->body.bf_sound[0].peer_mac,
+ txbfcfg->body.bf_sound_args.peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_sound[0].status = txbfcfg->body.bf_sound_args.status;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ memcpy(pmadapter, txbf->body.bf_periodicity->peer_mac,
+ txbfcfg->body.bf_periodicity.peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_periodicity->interval =
+ wlan_le16_to_cpu(txbfcfg->body.bf_periodicity.interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ txbf->no_of_peers = *(t_u8 *) & txbfcfg->body;
+ tx_bf_peer =
+ (bf_peer_args *) ((t_u8 *) & txbfcfg->body + sizeof(t_u8));
+ for (i = 0; i < txbf->no_of_peers; i++) {
+ memcpy(pmadapter, txbf->body.tx_bf_peer[i].peer_mac,
+ (t_u8 *) tx_bf_peer->peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.tx_bf_peer[i].bf_enbl = tx_bf_peer->bf_enbl;
+ txbf->body.tx_bf_peer[i].sounding_enbl =
+ tx_bf_peer->sounding_enbl;
+ txbf->body.tx_bf_peer[i].fb_type = tx_bf_peer->fb_type;
+ tx_bf_peer++;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ txbf->no_of_peers = *(t_u8 *) & txbfcfg->body;
+ bf_snr = (bf_snr_thr_t *) ((t_u8 *) & txbfcfg->body + sizeof(t_u8));
+ for (i = 0; i < txbf->no_of_peers; i++) {
+ memcpy(pmadapter, txbf->body.bf_snr[i].peer_mac,
+ (t_u8 *) bf_snr->peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_snr[i].snr = bf_snr->snr;
+ bf_snr++;
+ }
+ break;
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief This function append the 802_11N tlv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int
+wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc, OUT t_u8 ** ppbuffer)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIETypes_HTInfo_t *pht_info;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list;
+ MrvlIETypes_2040BSSCo_t *p2040_bss_co;
+ MrvlIETypes_ExtCap_t *pext_cap;
+ t_u32 usr_dot_11n_dev_cap;
+ int ret_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ if (pbss_desc->bss_band & 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 (pbss_desc->pht_cap) {
+ pht_cap = (MrvlIETypes_HTCap_t *) * ppbuffer;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ memcpy(pmadapter, (t_u8 *) pht_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pht_cap + sizeof(IEEEtypes_Header_t),
+ pht_cap->header.len);
+
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
+ pht_cap->ht_cap.ht_ext_cap =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_ext_cap);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pbss_desc->bss_band);
+
+ HEXDUMP("HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
+ ret_len += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ if (pbss_desc->pht_info) {
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ pht_info = (MrvlIETypes_HTInfo_t *) * ppbuffer;
+ memset(pmadapter, pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
+ pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
+ pht_info->header.len = sizeof(HTInfo_t);
+
+ memcpy(pmadapter, (t_u8 *) pht_info + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pht_info + sizeof(IEEEtypes_Header_t),
+ pht_info->header.len);
+
+ if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap)) {
+ RESET_CHANWIDTH40(pht_info->ht_info.field2);
+ }
+
+ *ppbuffer += sizeof(MrvlIETypes_HTInfo_t);
+ ret_len += sizeof(MrvlIETypes_HTInfo_t);
+ pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
+ }
+
+ pchan_list = (MrvlIEtypes_ChanListParamSet_t *) * ppbuffer;
+ memset(pmadapter, pchan_list, 0,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_list->header.len = sizeof(MrvlIEtypes_ChanListParamSet_t) -
+ sizeof(MrvlIEtypesHeader_t);
+ pchan_list->chan_scan_param[0].chan_number =
+ pbss_desc->pht_info->ht_info.pri_chan;
+ pchan_list->chan_scan_param[0].radio_type =
+ wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
+ ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2)) {
+ SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
+ GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.
+ field2));
+ }
+
+ HEXDUMP("ChanList", (t_u8 *) pchan_list,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ HEXDUMP("pht_info", (t_u8 *) pbss_desc->pht_info,
+ sizeof(MrvlIETypes_HTInfo_t) - 2);
+ *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ pchan_list->header.len = wlan_cpu_to_le16(pchan_list->header.len);
+ }
+
+ if (pbss_desc->pbss_co_2040) {
+ p2040_bss_co = (MrvlIETypes_2040BSSCo_t *) * ppbuffer;
+ memset(pmadapter, p2040_bss_co, 0, sizeof(MrvlIETypes_2040BSSCo_t));
+ p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
+ p2040_bss_co->header.len = sizeof(BSSCo2040_t);
+
+ memcpy(pmadapter, (t_u8 *) p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pbss_co_2040 + sizeof(IEEEtypes_Header_t),
+ p2040_bss_co->header.len);
+
+ HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *) p2040_bss_co,
+ sizeof(MrvlIETypes_2040BSSCo_t));
+ *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
+ ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
+ p2040_bss_co->header.len = wlan_cpu_to_le16(p2040_bss_co->header.len);
+ }
+
+ if (pbss_desc->pext_cap) {
+ pext_cap = (MrvlIETypes_ExtCap_t *) * ppbuffer;
+ memset(pmadapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
+ pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
+ pext_cap->header.len = sizeof(ExtCap_t);
+
+ memcpy(pmadapter, (t_u8 *) pext_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pext_cap + sizeof(IEEEtypes_Header_t),
+ pbss_desc->pext_cap->ieee_hdr.len);
+ HEXDUMP("Extended Capabilities IE", (t_u8 *) pext_cap,
+ sizeof(MrvlIETypes_ExtCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
+ ret_len += sizeof(MrvlIETypes_ExtCap_t);
+ pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
+ }
+ LEAVE();
+ return ret_len;
+}
+
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief 11n configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11n_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11n_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ switch (cfg->sub_command) {
+ case MLAN_OID_11N_CFG_TX:
+ status = wlan_11n_ioctl_httxcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_HTCAP_CFG:
+ status = wlan_11n_ioctl_htusrcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AGGR_PRIO_TBL:
+ status = wlan_11n_ioctl_aggr_prio_tbl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_REJECT:
+ status = wlan_11n_ioctl_addba_reject(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_PARAM:
+ status = wlan_11n_ioctl_addba_param(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE:
+ status = wlan_11n_ioctl_max_tx_buf_size(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL:
+ status = wlan_11n_ioctl_amsdu_aggr_ctrl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_SUPPORTED_MCS_SET:
+ status = wlan_11n_ioctl_supported_mcs_set(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_TX_BF_CAP:
+ status = wlan_11n_ioctl_tx_bf_cap(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_TX_BF_CFG:
+ status = wlan_11n_ioctl_tx_bf_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_STREAM_CFG:
+ status = wlan_11n_ioctl_stream_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function will delete the given entry in Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptx_tbl Pointer to tx ba stream entry to delete
+ *
+ * @return N/A
+ */
+void
+wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,
+ TxBAStreamTbl * ptx_tbl)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->tx_ba_stream_tbl_ptr.plock);
+
+ if (!ptx_tbl || !wlan_is_txbastreamptr_valid(priv, ptx_tbl)) {
+ goto exit;
+ }
+
+ PRINTM(MINFO, "Delete BA stream table entry: %p\n", ptx_tbl);
+
+ util_unlink_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list) ptx_tbl, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *) ptx_tbl);
+
+ exit:
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->tx_ba_stream_tbl_ptr.plock);
+ LEAVE();
+}
+
+/**
+ * @brief This function will delete all the entries in Tx BA Stream table
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_deleteall_txbastream_tbl(mlan_private * priv)
+{
+ int i;
+ TxBAStreamTbl *del_tbl_ptr = MNULL;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (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))) {
+ wlan_11n_delete_txbastream_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list) & priv->tx_ba_stream_tbl_ptr);
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].ampdu_ap = priv->aggr_prio_tbl[i].ampdu_user;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will return the pointer to an entry in BA Stream
+ * table which matches the give RA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to find in reordering table
+ * @param ra RA to find in reordering table
+ *
+ * @return A pointer to first entry matching RA/TID in BA stream
+ * NULL if not found
+ */
+TxBAStreamTbl *
+wlan_11n_get_txbastream_tbl(mlan_private * priv, int tid, t_u8 * ra)
+{
+ TxBAStreamTbl *ptx_tbl;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!(ptx_tbl = (TxBAStreamTbl *) util_peek_list(pmadapter->pmoal_handle,
+ &priv->
+ tx_ba_stream_tbl_ptr,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", ptx_tbl->tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+
+ if ((!memcmp(pmadapter, ptx_tbl->ra, ra, MLAN_MAC_ADDR_LENGTH))
+ && (ptx_tbl->tid == tid)) {
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will create a entry in tx ba stream table for the
+ * given RA/TID.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in reordering table
+ * @param tid TID to find in reordering table
+ * @param ba_status BA stream status to create the stream with
+ *
+ * @return N/A
+ */
+void
+wlan_11n_create_txbastream_tbl(mlan_private * priv,
+ t_u8 * ra, int tid, baStatus_e ba_status)
+{
+ TxBAStreamTbl *newNode = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!wlan_11n_get_txbastream_tbl(priv, tid, ra)) {
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ra, MLAN_MAC_ADDR_LENGTH);
+
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(TxBAStreamTbl), MLAN_MEM_DEF,
+ (t_u8 **) & newNode);
+ util_init_list((pmlan_linked_list) newNode);
+
+ newNode->tid = tid;
+ newNode->ba_status = ba_status;
+ memcpy(pmadapter, newNode->ra, ra, MLAN_MAC_ADDR_LENGTH);
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list) newNode,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will send a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_send_addba(mlan_private * priv, int tid, t_u8 * peer_mac)
+{
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ static t_u8 dialog_tok;
+ mlan_status ret;
+
+ ENTER();
+
+ PRINTM(MCMND, "Send addba: TID %d\n", tid);
+ DBG_HEXDUMP(MCMD_D, "Send addba RA", peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ add_ba_req.block_ack_param_set = (t_u16) ((tid << BLOCKACKPARAM_TID_POS) |
+ (priv->add_ba_param.tx_win_size
+ << BLOCKACKPARAM_WINSIZE_POS) |
+ IMMEDIATE_BLOCK_ACK);
+ /** enable AMSDU inside AMPDU */
+ if (priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ add_ba_req.block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
+ add_ba_req.block_ack_tmo = (t_u16) priv->add_ba_param.timeout;
+
+ ++dialog_tok;
+
+ if (dialog_tok == 0)
+ dialog_tok = 1;
+
+ add_ba_req.dialog_token = dialog_tok;
+ memcpy(priv->adapter, &add_ba_req.peer_mac_addr, peer_mac,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
+ 0, 0, MNULL, &add_ba_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ * @param initiator MTRUE if we have initiated ADDBA, MFALSE otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_send_delba(mlan_private * priv, int tid, t_u8 * peer_mac, int initiator)
+{
+ HostCmd_DS_11N_DELBA delba;
+ mlan_status ret;
+
+ ENTER();
+
+ memset(priv->adapter, &delba, 0, sizeof(delba));
+ delba.del_ba_param_set = (tid << DELBA_TID_POS);
+
+ if (initiator)
+ DELBA_INITIATOR(delba.del_ba_param_set);
+ else
+ DELBA_RECIPIENT(delba.del_ba_param_set);
+
+ memcpy(priv->adapter, &delba.peer_mac_addr, peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &delba);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param del_ba A pointer to command response buffer
+ *
+ * @return N/A
+ */
+void
+wlan_11n_delete_bastream(mlan_private * priv, t_u8 * del_ba)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *) del_ba;
+ int tid;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Delba:", (t_u8 *) pdel_ba, 20);
+ 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;
+
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_RECEIVE,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set));
+
+ LEAVE();
+}
+
+/**
+ * @brief Get Rx reordering table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to rx_reorder_tbl structure
+ * @return number of rx reorder table entry
+ */
+int
+wlan_get_rxreorder_tbl(mlan_private * priv, rx_reorder_tbl * buf)
+{
+ int i;
+ rx_reorder_tbl *ptbl = buf;
+ RxReorderTbl *rxReorderTblPtr;
+ int count = 0;
+ ENTER();
+ if (!
+ (rxReorderTblPtr =
+ (RxReorderTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return count;
+ }
+ while (rxReorderTblPtr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ ptbl->tid = (t_u16) rxReorderTblPtr->tid;
+ memcpy(priv->adapter, ptbl->ta, rxReorderTblPtr->ta,
+ MLAN_MAC_ADDR_LENGTH);
+ ptbl->start_win = rxReorderTblPtr->start_win;
+ ptbl->win_size = rxReorderTblPtr->win_size;
+ ptbl->amsdu = rxReorderTblPtr->amsdu;
+ for (i = 0; i < rxReorderTblPtr->win_size; ++i) {
+ if (rxReorderTblPtr->rx_reorder_ptr[i])
+ ptbl->buffer[i] = MTRUE;
+ else
+ ptbl->buffer[i] = MFALSE;
+ }
+ rxReorderTblPtr = rxReorderTblPtr->pnext;
+ ptbl++;
+ count++;
+ if (count >= MLAN_MAX_RX_BASTREAM_SUPPORTED)
+ break;
+ }
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief Get transmit BA stream table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to tx_ba_stream_tbl structure
+ * @return number of ba stream table entry
+ */
+int
+wlan_get_txbastream_tbl(mlan_private * priv, tx_ba_stream_tbl * buf)
+{
+ TxBAStreamTbl *ptxtbl;
+ tx_ba_stream_tbl *ptbl = buf;
+ int count = 0;
+
+ ENTER();
+
+ if (!(ptxtbl = (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 count;
+ }
+
+ while (ptxtbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ ptbl->tid = (t_u16) ptxtbl->tid;
+ PRINTM(MINFO, "tid=%d\n", ptbl->tid);
+ memcpy(priv->adapter, ptbl->ra, ptxtbl->ra, MLAN_MAC_ADDR_LENGTH);
+ ptbl->amsdu = ptxtbl->amsdu;
+ ptxtbl = ptxtbl->pnext;
+ ptbl++;
+ count++;
+ if (count >= MLAN_MAX_TX_BASTREAM_SUPPORTED)
+ break;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function cleans up txbastream_tbl for specific station
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in txbastream_tbl
+ * @return N/A
+ */
+void
+wlan_11n_cleanup_txbastream_tbl(mlan_private * priv, t_u8 * ra)
+{
+ TxBAStreamTbl *ptx_tbl = MNULL;
+ t_u8 i;
+ ENTER();
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, i, ra))) {
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptx_tbl);
+ }
+ }
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n.h b/drivers/net/wireless/sd8797/mlan/mlan_11n.h
new file mode 100644
index 000000000000..3b83ad75ebcb
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n.h
@@ -0,0 +1,420 @@
+/** @file mlan_11n.h
+ *
+ * @brief Interface for the 802.11n mlan_11n module implemented in mlan_11n.c
+ *
+ * Driver interface functions and type declarations for the 11n module
+ * implemented in mlan_11n.c.
+ *
+ * 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:
+ 12/01/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_H_
+#define _MLAN_11N_H_
+
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#include "mlan_wmm.h"
+
+/** Print the 802.11n device capability */
+void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap);
+/** Print the 802.11n device MCS */
+void wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support);
+/** Handle the command response of a delete block ack request */
+mlan_status wlan_ret_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * resp);
+/** Handle the command response of an add block ack request */
+mlan_status wlan_ret_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * resp);
+/** Handle the command response of 11ncfg command */
+mlan_status wlan_ret_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+/** Prepare 11ncfg command */
+mlan_status wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+/** Prepare TX BF configuration command */
+mlan_status wlan_cmd_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+/** Handle the command response TX BF configuration */
+mlan_status wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+#ifdef STA_SUPPORT
+/** Append the 802_11N tlv */
+int wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc,
+ OUT t_u8 ** ppbuffer);
+/** wlan fill HT cap tlv */
+void wlan_fill_ht_cap_tlv(mlan_private * priv, MrvlIETypes_HTCap_t * pht_cap,
+ t_u8 band);
+#endif /* STA_SUPPORT */
+/** Miscellaneous configuration handler */
+mlan_status wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** Delete Tx BA stream table entry */
+void wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,
+ TxBAStreamTbl * ptx_tbl);
+/** Delete all Tx BA stream table entries */
+void wlan_11n_deleteall_txbastream_tbl(mlan_private * priv);
+/** Get Tx BA stream table */
+TxBAStreamTbl *wlan_11n_get_txbastream_tbl(mlan_private * priv, int tid,
+ t_u8 * ra);
+/** Create Tx BA stream table */
+void wlan_11n_create_txbastream_tbl(mlan_private * priv, t_u8 * ra, int tid,
+ baStatus_e ba_status);
+/** Send ADD BA request */
+int wlan_send_addba(mlan_private * priv, int tid, t_u8 * peer_mac);
+/** Send DEL BA request */
+int wlan_send_delba(mlan_private * priv, int tid, t_u8 * peer_mac,
+ int initiator);
+/** This function handles the command response of delete a block ack request*/
+void wlan_11n_delete_bastream(mlan_private * priv, t_u8 * del_ba);
+/** get rx reorder table */
+int wlan_get_rxreorder_tbl(mlan_private * priv, rx_reorder_tbl * buf);
+/** get tx ba stream table */
+int wlan_get_txbastream_tbl(mlan_private * priv, tx_ba_stream_tbl * buf);
+/** Minimum number of AMSDU */
+#define MIN_NUM_AMSDU 2
+/** AMSDU Aggr control cmd resp */
+mlan_status wlan_ret_amsdu_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+/** reconfigure tx buf size */
+mlan_status wlan_cmd_recfg_tx_buf(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf);
+/** AMSDU aggr control cmd */
+mlan_status wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf);
+
+/** clean up txbastream_tbl */
+void wlan_11n_cleanup_txbastream_tbl(mlan_private * priv, t_u8 * ra);
+/**
+ * @brief This function checks whether a station has 11N enabled or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station mac address
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+is_station_11n_enabled(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, mac))) {
+ return (sta_ptr->is_11n_enabled) ? MTRUE : MFALSE;
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function get station max amsdu size
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station mac address
+ * @return max amsdu size statio supported
+ */
+static INLINE t_u16
+get_station_max_amsdu_size(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, mac))) {
+ return sta_ptr->max_amsdu;
+ }
+ return 0;
+}
+
+/**
+ * @brief This function checks whether a station allows AMPDU or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+is_station_ampdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, ptr->ra))) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (priv->sec_info.wapi_enabled && !sta_ptr->wapi_key_on)
+ return MFALSE;
+ }
+ return ((sta_ptr->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED)
+ ? MTRUE : MFALSE);
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function disable station ampdu for specific tid
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid index
+ * @param ra station mac address
+ * @return N/A
+ */
+static INLINE void
+disable_station_ampdu(mlan_private * priv, t_u8 tid, t_u8 * ra)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, ra))) {
+ sta_ptr->ampdu_sta[tid] = BA_STREAM_NOT_ALLOWED;
+ }
+ return;
+}
+
+/**
+ * @brief This function checks whether current BA stream is high priority or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_cur_bastream_high_prio(mlan_private * priv, int tid)
+{
+ 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)))
+ return MFALSE;
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (priv->aggr_prio_tbl[tid].ampdu_user >
+ priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether AMPDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_ampdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ return is_station_ampdu_allowed(priv, ptr, tid);
+#endif /* UAP_SUPPORT */
+ if (priv->sec_info.wapi_enabled && !priv->sec_info.wapi_key_on)
+ return MFALSE;
+
+ return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
+ ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function checks whether AMSDU is allowed for BA stream
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_amsdu_in_ampdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+ TxBAStreamTbl *ptx_tbl;
+ ENTER();
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, tid, ptr->ra))) {
+ LEAVE();
+ return ptx_tbl->amsdu;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether AMSDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_amsdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+#ifdef UAP_SUPPORT
+ sta_node *sta_ptr = MNULL;
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((sta_ptr = wlan_get_station_entry(priv, ptr->ra))) {
+ if (priv->sec_info.wapi_enabled && !sta_ptr->wapi_key_on)
+ return MFALSE;
+ }
+ }
+#endif /* UAP_SUPPORT */
+#define TXRATE_BITMAP_INDEX_MCS0_7 2
+ return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
+ && ((priv->is_data_rate_auto)
+ || !((priv->bitmap_rates[TXRATE_BITMAP_INDEX_MCS0_7]) & 0x03)))
+ ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function checks whether a BA stream is available or not
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_bastream_avail(mlan_private * priv)
+{
+ mlan_private *pmpriv = MNULL;
+ t_u8 i = 0;
+ t_u32 bastream_num = 0;
+ for (i = 0; i < priv->adapter->priv_num; i++) {
+ if ((pmpriv = priv->adapter->priv[i]))
+ bastream_num +=
+ wlan_wmm_list_len(priv->adapter,
+ (pmlan_list_head) & pmpriv->
+ tx_ba_stream_tbl_ptr);
+ }
+ return ((bastream_num < MLAN_MAX_TX_BASTREAM_SUPPORTED) ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function finds the stream to delete
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptr_tid TID value of ptr
+ * @param ptid A pointer to TID of stream to delete, if return MTRUE
+ * @param ra RA of stream to delete, if return MTRUE
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_find_stream_to_delete(mlan_private * priv,
+ raListTbl * ptr, int ptr_tid, int *ptid, t_u8 * ra)
+{
+ int tid;
+ t_u8 ret = MFALSE;
+ 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 ret;
+ }
+
+ tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (tid > priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ tid = priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user;
+ *ptid = ptx_tbl->tid;
+ memcpy(priv->adapter, ra, ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+ ret = MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks whether BA stream is setup
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_bastream_setup(mlan_private * priv, raListTbl * ptr, int tid)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, tid, ptr->ra))) {
+ LEAVE();
+ return IS_BASTREAM_SETUP(ptx_tbl) ? MTRUE : MFALSE;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether 11n is supported
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_11n_enabled(mlan_private * priv, t_u8 * ra)
+{
+ int ret = MFALSE;
+ ENTER();
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((!(ra[0] & 0x01)) && (priv->is_11n_enabled))
+ ret = is_station_11n_enabled(priv, ra);
+ }
+#endif /* UAP_SUPPORT */
+ LEAVE();
+ return ret;
+}
+#endif /* !_MLAN_11N_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
new file mode 100644
index 000000000000..6125262d5b7a
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
@@ -0,0 +1,509 @@
+/** @file mlan_11n_aggr.c
+ *
+ * @brief This file contains functions for 11n Aggregation.
+ *
+ * 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"
+#include "mlan_11n_aggr.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Aggregate individual packets into one AMSDU packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param amsdu_buf A pointer to packet buffer
+ * @param data A pointer to aggregated data packet being formed
+ * @param pkt_len Length of current packet to aggregate
+ * @param pad Pad
+ *
+ * @return Final packet size
+ */
+static int
+wlan_11n_form_amsdu_pkt(pmlan_adapter pmadapter, t_u8 * amsdu_buf, t_u8 * data,
+ int pkt_len, int *pad)
+{
+ int dt_offset, amsdu_buf_offset;
+ Rfc1042Hdr_t snap = {
+ 0xaa, /* LLC DSAP */
+ 0xaa, /* LLC SSAP */
+ 0x03, /* LLC CTRL */
+ {0x00, 0x00, 0x00}, /* SNAP OUI */
+ 0x0000 /* SNAP type */
+ /*
+ * This field will be overwritten
+ * later with ethertype
+ */
+ };
+
+ ENTER();
+
+ memcpy(pmadapter, amsdu_buf, data, (MLAN_MAC_ADDR_LENGTH) * 2);
+ dt_offset = amsdu_buf_offset = (MLAN_MAC_ADDR_LENGTH) * 2;
+
+ snap.snap_type = *(t_u16 *) (data + dt_offset);
+ dt_offset += sizeof(t_u16);
+ *(t_u16 *) (amsdu_buf + amsdu_buf_offset) = mlan_htons(pkt_len +
+ LLC_SNAP_LEN -
+ ((2 *
+ MLAN_MAC_ADDR_LENGTH)
+ + sizeof(t_u16)));
+ amsdu_buf_offset += sizeof(t_u16);
+ memcpy(pmadapter, amsdu_buf + amsdu_buf_offset, &snap, LLC_SNAP_LEN);
+ amsdu_buf_offset += LLC_SNAP_LEN;
+
+ memcpy(pmadapter, amsdu_buf + amsdu_buf_offset, data + dt_offset,
+ pkt_len - dt_offset);
+ *pad =
+ (((pkt_len + LLC_SNAP_LEN) & 3)) ? (4 -
+ (((pkt_len +
+ LLC_SNAP_LEN)) & 3)) : 0;
+
+ LEAVE();
+ return (pkt_len + LLC_SNAP_LEN + *pad);
+}
+
+/**
+ * @brief Add TxPD to AMSDU header
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf Pointer to buffer where the TxPD will be formed
+ *
+ * @return N/A
+ */
+static void
+wlan_11n_form_amsdu_txpd(mlan_private * priv, mlan_buffer * mbuf)
+{
+ TxPD *ptx_pd;
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+
+ ptx_pd = (TxPD *) mbuf->pbuf;
+ memset(pmadapter, ptx_pd, 0, sizeof(TxPD));
+
+ /*
+ * Original priority has been overwritten
+ */
+ ptx_pd->priority = (t_u8) mbuf->priority;
+ ptx_pd->pkt_delay_2ms = wlan_wmm_compute_driver_packet_delay(priv, mbuf);
+ ptx_pd->bss_num = GET_BSS_NUM(priv);
+ ptx_pd->bss_type = priv->bss_type;
+ /* Always zero as the data is followed by TxPD */
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ ptx_pd->tx_pkt_type = PKT_TYPE_AMSDU;
+
+ if (ptx_pd->tx_control == 0)
+ /* TxCtrl set by user or default */
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+
+ endian_convert_TxPD(ptx_pd);
+
+ LEAVE();
+}
+
+/**
+ * @brief Update the TxPktLength field in TxPD after the complete AMSDU
+ * packet is formed
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf TxPD buffer
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_11n_update_pktlen_amsdu_txpd(mlan_private * priv, pmlan_buffer mbuf)
+{
+ TxPD *ptx_pd;
+ ENTER();
+
+ ptx_pd = (TxPD *) mbuf->pbuf;
+ ptx_pd->tx_pkt_length =
+ (t_u16) wlan_cpu_to_le16(mbuf->data_len - sizeof(TxPD));
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->adapter->pps_uapsd_mode)) {
+ if (MTRUE == wlan_check_last_packet_indication(priv)) {
+ priv->adapter->tx_lock_flag = MTRUE;
+ ptx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+#endif /* STA_SUPPORT */
+ LEAVE();
+}
+
+/**
+ * @brief Get number of aggregated packets
+ *
+ * @param data A pointer to packet data
+ * @param total_pkt_len Total packet length
+ *
+ * @return Number of packets
+ */
+static int
+wlan_11n_get_num_aggrpkts(t_u8 * data, int total_pkt_len)
+{
+ int pkt_count = 0, pkt_len, pad;
+
+ ENTER();
+ while (total_pkt_len > 0) {
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;
+ data += pkt_len + pad + sizeof(Eth803Hdr_t);
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+ ++pkt_count;
+ }
+ LEAVE();
+ return pkt_count;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Deaggregate the received AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to aggregated data packet
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf)
+{
+ t_u16 pkt_len;
+ int total_pkt_len;
+ t_u8 *data;
+ int pad;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ RxPacketHdr_t *prx_pkt;
+ mlan_buffer *daggr_mbuf = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03,
+ 0x00, 0x00, 0x00
+ };
+
+ ENTER();
+
+ data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ total_pkt_len = pmbuf->data_len;
+
+ /* Sanity test */
+ if (total_pkt_len > MLAN_RX_DATA_BUF_SIZE) {
+ PRINTM(MERROR, "Total packet length greater than tx buffer"
+ " size %d\n", total_pkt_len);
+ goto done;
+ }
+
+ pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len);
+
+ while (total_pkt_len > 0) {
+ prx_pkt = (RxPacketHdr_t *) data;
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ if (pkt_len > total_pkt_len) {
+ PRINTM(MERROR,
+ "Error in packet length: total_pkt_len = %d, pkt_len = %d\n",
+ total_pkt_len, pkt_len);
+ break;
+ }
+
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;
+
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+
+ if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+ memmove(pmadapter, data + LLC_SNAP_LEN, data, (2 *
+ MLAN_MAC_ADDR_LENGTH));
+ data += LLC_SNAP_LEN;
+ pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN;
+ } else {
+ *(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))
+ = (t_u16) 0;
+ pkt_len += sizeof(Eth803Hdr_t);
+ }
+ daggr_mbuf = wlan_alloc_mlan_buffer(pmadapter, pkt_len, 0, MFALSE);
+ if (daggr_mbuf == MNULL) {
+ PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ daggr_mbuf->bss_index = pmbuf->bss_index;
+ daggr_mbuf->buf_type = pmbuf->buf_type;
+ daggr_mbuf->data_len = pkt_len;
+ daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec;
+ daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec;
+ daggr_mbuf->pparent = pmbuf;
+ daggr_mbuf->priority = pmbuf->priority;
+ memcpy(pmadapter, daggr_mbuf->pbuf + daggr_mbuf->data_offset, data,
+ pkt_len);
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ ret = wlan_uap_recv_packet(priv, daggr_mbuf);
+ else
+#endif /* UAP_SUPPORT */
+ ret =
+ pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ daggr_mbuf);
+
+ switch (ret) {
+ case MLAN_STATUS_PENDING:
+ break;
+ case MLAN_STATUS_FAILURE:
+ PRINTM(MERROR, "Deaggr, send to moal failed\n");
+ daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ case MLAN_STATUS_SUCCESS:
+ wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ data += pkt_len + pad;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Aggregate multiple packets into one single AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pra_list Pointer to the RA List table containing the pointers
+ * to packets.
+ * @param headroom Any interface specific headroom that may be need. TxPD
+ * will be formed leaving this headroom.
+ * @param ptrindex Pointer index
+ *
+ * @return Final packet size or MLAN_STATUS_FAILURE
+ */
+int
+wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list,
+ int headroom, int ptrindex)
+{
+ int pkt_size = 0;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_buffer *pmbuf_aggr, *pmbuf_src;
+ t_u8 *data;
+ int pad = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+ mlan_tx_param tx_param;
+#ifdef STA_SUPPORT
+ TxPD *ptx_pd = MNULL;
+#endif
+ t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size);
+ ENTER();
+
+ PRINTM(MDAT_D, "Handling Aggr packet\n");
+
+ if ((pmbuf_src =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &pra_list->buf_head, MNULL, MNULL))) {
+
+ if (!(pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter,
+ pmadapter->tx_buf_size, 0,
+ MTRUE))) {
+ PRINTM(MERROR, "Error allocating mlan_buffer\n");
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ data = pmbuf_aggr->pbuf + headroom;
+ pmbuf_aggr->bss_index = pmbuf_src->bss_index;
+ pmbuf_aggr->buf_type = pmbuf_src->buf_type;
+ pmbuf_aggr->priority = pmbuf_src->priority;
+ pmbuf_aggr->pbuf = data;
+ pmbuf_aggr->data_offset = 0;
+
+ /* Form AMSDU */
+ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr);
+ pkt_size = sizeof(TxPD);
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ ptx_pd = (TxPD *) pmbuf_aggr->pbuf;
+#endif
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ goto exit;
+ }
+
+ while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN)
+ + headroom) <= max_amsdu_size)) {
+
+ pmbuf_src = (pmlan_buffer)
+ util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head,
+ MNULL, MNULL);
+
+ pra_list->total_pkts--;
+
+ /* decrement for every PDU taken from the list */
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ pkt_size += wlan_11n_form_amsdu_pkt(pmadapter,
+ (data + pkt_size),
+ pmbuf_src->pbuf +
+ pmbuf_src->data_offset,
+ pmbuf_src->data_len, &pad);
+
+ DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src, sizeof(mlan_buffer));
+ wlan_write_data_complete(pmadapter, pmbuf_src, MLAN_STATUS_SUCCESS);
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf_src =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &pra_list->buf_head, MNULL, MNULL);
+ }
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ /* Last AMSDU packet does not need padding */
+ pkt_size -= pad;
+ pmbuf_aggr->data_len = pkt_size;
+ wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr);
+ pmbuf_aggr->data_len += headroom;
+ pmbuf_aggr->pbuf = data - headroom;
+ tx_param.next_pkt_len = ((pmbuf_src) ?
+ pmbuf_src->data_len + sizeof(TxPD) : 0);
+
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA,
+ pmbuf_aggr, &tx_param);
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr,
+ MLAN_STATUS_FAILURE);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef STA_SUPPORT
+ /* reset tx_lock_flag */
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) {
+ pmadapter->tx_lock_flag = MFALSE;
+ ptx_pd->flags = 0;
+ }
+#endif
+ util_enqueue_list_head(pmadapter->pmoal_handle, &pra_list->buf_head,
+ (pmlan_linked_list) pmbuf_aggr, MNULL, MNULL);
+
+ pra_list->total_pkts++;
+
+ /* add back only one: aggregated packet is requeued as one */
+ priv->wmm.pkts_queued[ptrindex]++;
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
+ pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ goto exit;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_SUCCESS:
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
+
+ exit:
+ LEAVE();
+ return (pkt_size + headroom);
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h
new file mode 100644
index 000000000000..ef8108a764c0
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h
@@ -0,0 +1,37 @@
+/** @file mlan_11n_aggr.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n aggregation functionalities
+ *
+ * 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
+********************************************************/
+
+#ifndef _MLAN_11N_AGGR_H_
+#define _MLAN_11N_AGGR_H_
+
+/** Aggregate 11N packets */
+mlan_status wlan_11n_deaggregate_pkt(pmlan_private priv, pmlan_buffer pmbuf);
+/** Deaggregate 11N packets */
+int wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * ptr,
+ int headroom, int ptrindex);
+
+#endif /* !_MLAN_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
new file mode 100644
index 000000000000..af689b7bab49
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
@@ -0,0 +1,1138 @@
+/** @file mlan_11n_rxreorder.c
+ *
+ * @brief This file contains the handling of RxReordering in wlan
+ * driver.
+ *
+ * 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"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function will dispatch amsdu packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_dispatch_amsdu_pkt(mlan_private * priv, pmlan_buffer pmbuf)
+{
+ RxPD *prx_pd;
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+
+ ENTER();
+ if (prx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+ pmbuf->data_len = prx_pd->rx_pkt_length;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ wlan_11n_deaggregate_pkt(priv, pmbuf);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function will process the rx packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param payload A pointer to rx packet payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_dispatch_pkt(t_void * priv, t_void * payload)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ pmlan_adapter pmadapter = ((pmlan_private) priv)->adapter;
+#endif
+ ENTER();
+ if (payload == (t_void *) RX_PKT_DROPPED_IN_FW) {
+ LEAVE();
+ return ret;
+ }
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE((mlan_private *) priv) == MLAN_BSS_ROLE_UAP) {
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_11n_dispatch_amsdu_pkt((mlan_private *) priv,
+ (pmlan_buffer) payload)) {
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_process_uap_rx_packet(priv, (pmlan_buffer) payload);
+ LEAVE();
+ return ret;
+ }
+#endif /* UAP_SUPPORT */
+
+#ifdef STA_SUPPORT
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_11n_dispatch_amsdu_pkt((mlan_private *) priv,
+ (pmlan_buffer) payload)) {
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer) payload);
+#endif /* STA_SUPPORT */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function restarts the reordering timeout timer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static void
+mlan_11n_rxreorder_timer_restart(pmlan_adapter pmadapter,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ ENTER();
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ pmadapter->callbacks.moal_stop_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.
+ timer);
+
+ pmadapter->callbacks.moal_start_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.timer,
+ MFALSE,
+ (rx_reor_tbl_ptr->win_size
+ * MIN_FLUSH_TIMER_MS));
+
+ rx_reor_tbl_ptr->timer_context.timer_is_set = MTRUE;
+ LEAVE();
+}
+
+/**
+ * @brief This function dispatches all the packets in the buffer.
+ * There could be holes in the buffer.
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ * @param start_win Start window
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11n_dispatch_pkt_until_start_win(t_void * priv,
+ RxReorderTbl * rx_reor_tbl_ptr,
+ int start_win)
+{
+ int no_pkt_to_send, i, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *) priv;
+
+ ENTER();
+
+ no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
+ MIN((start_win - rx_reor_tbl_ptr->start_win),
+ rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
+
+ for (i = 0; i < no_pkt_to_send; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ rx_tmp_ptr = MNULL;
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ }
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
+ pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ if (rx_tmp_ptr)
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
+ for (i = 0; i < xchg; ++i) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = MNULL;
+ }
+
+ rx_reor_tbl_ptr->start_win = start_win;
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will display the rxReorder table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ ENTER();
+
+ DBG_HEXDUMP(MDAT_D, "Reorder ptr", rx_reor_tbl_ptr->rx_reorder_ptr,
+ sizeof(t_void *) * rx_reor_tbl_ptr->win_size);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will dispatch all packets sequentially
+ * from start_win until a hole is found and adjust the
+ * start_win appropriately
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11n_scan_and_dispatch(t_void * priv, RxReorderTbl * rx_reor_tbl_ptr)
+{
+ int i, j, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *) priv;
+
+ ENTER();
+
+ for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
+ pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ break;
+ }
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
+ pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ if (i > 0) {
+ xchg = rx_reor_tbl_ptr->win_size - i;
+ for (j = 0; j < xchg; ++j) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[j] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = MNULL;
+ }
+ }
+
+ rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
+ & (MAX_TID_VALUE - 1);
+
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function delete rxreorder table's entry
+ * and free the memory
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_delete_rxreorder_tbl_entry(mlan_private * priv,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+
+ wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+ (rx_reor_tbl_ptr->start_win +
+ rx_reor_tbl_ptr->win_size)
+ & (MAX_TID_VALUE - 1));
+
+ if (rx_reor_tbl_ptr->timer_context.timer) {
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ priv->adapter->callbacks.moal_stop_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.
+ timer);
+ priv->adapter->callbacks.moal_free_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.
+ timer);
+ }
+
+ PRINTM(MDAT_D, "Delete rx_reor_tbl_ptr: %p\n", rx_reor_tbl_ptr);
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list) rx_reor_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) rx_reor_tbl_ptr->rx_reorder_ptr);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) rx_reor_tbl_ptr);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the last used sequence number
+ *
+ * @param rx_reorder_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return Last used sequence number
+ */
+static int
+wlan_11n_find_last_seqnum(RxReorderTbl * rx_reorder_tbl_ptr)
+{
+ int i;
+
+ ENTER();
+ for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) {
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
+ LEAVE();
+ return i;
+ }
+ }
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief This function flushes all data
+ *
+ * @param context Reorder context pointer
+ *
+ * @return N/A
+ */
+static t_void
+wlan_flush_data(t_void * context)
+{
+ reorder_tmr_cnxt_t *reorder_cnxt = (reorder_tmr_cnxt_t *) context;
+ int startWin;
+
+ ENTER();
+ reorder_cnxt->timer_is_set = MFALSE;
+ wlan_11n_display_tbl_ptr(reorder_cnxt->priv->adapter, reorder_cnxt->ptr);
+
+ if ((startWin = wlan_11n_find_last_seqnum(reorder_cnxt->ptr)) >= 0) {
+ PRINTM(MINFO, "Flush data %d\n", startWin);
+ wlan_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
+ reorder_cnxt->ptr,
+ ((reorder_cnxt->ptr->start_win +
+ startWin + 1) & (MAX_TID_VALUE -
+ 1)));
+ }
+
+ wlan_11n_display_tbl_ptr(reorder_cnxt->priv->adapter, reorder_cnxt->ptr);
+ LEAVE();
+}
+
+/**
+ * @brief This function will create a entry in rx reordering table for the
+ * given ta/tid and will initialize it with seq_num, win_size
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ * @param win_size win_size for the give ta/tid pair.
+ * @param seq_num Starting sequence number for current entry.
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_create_rxreorder_tbl(mlan_private * priv, t_u8 * ta, int tid,
+ int win_size, int seq_num)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ RxReorderTbl *rx_reor_tbl_ptr, *new_node;
+ sta_node *sta_ptr = MNULL;
+ t_u16 last_seq = 0;
+
+ ENTER();
+
+ /*
+ * If we get a TID, ta pair which is already present dispatch all the
+ * the packets and move the window size until the ssn
+ */
+ if ((rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta))) {
+ wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, seq_num);
+ } else {
+ PRINTM(MDAT_D, "%s: seq_num %d, tid %d, ta %02x:%02x:%02x:%02x:"
+ "%02x:%02x, win_size %d\n", __FUNCTION__,
+ seq_num, tid, ta[0], ta[1], ta[2], ta[3],
+ ta[4], ta[5], win_size);
+ if (pmadapter->callbacks.
+ moal_malloc(pmadapter->pmoal_handle, sizeof(RxReorderTbl),
+ MLAN_MEM_DEF, (t_u8 **) & new_node)) {
+ PRINTM(MERROR, "Rx reorder memory allocation failed\n");
+ LEAVE();
+ return;
+ }
+
+ util_init_list((pmlan_linked_list) new_node);
+ new_node->tid = tid;
+ memcpy(pmadapter, new_node->ta, ta, MLAN_MAC_ADDR_LENGTH);
+ new_node->start_win = seq_num;
+ if (queuing_ra_based(priv)) {
+ // TODO for adhoc
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((sta_ptr = wlan_get_station_entry(priv, ta)))
+ last_seq = sta_ptr->rx_seq[tid];
+ }
+ PRINTM(MINFO, "UAP/ADHOC:last_seq=%d start_win=%d\n", last_seq,
+ new_node->start_win);
+ } else {
+ last_seq = priv->rx_seq[tid];
+ }
+ if ((last_seq != DEFAULT_SEQ_NUM) && (last_seq >= new_node->start_win)) {
+ PRINTM(MDAT_D, "Update start_win: last_seq=%d, start_win=%d\n",
+ last_seq, new_node->start_win);
+ new_node->start_win = last_seq + 1;
+ }
+ new_node->win_size = win_size;
+
+ if (pmadapter->callbacks.
+ moal_malloc(pmadapter->pmoal_handle, sizeof(t_void *) * win_size,
+ MLAN_MEM_DEF, (t_u8 **) & new_node->rx_reorder_ptr)) {
+ PRINTM(MERROR, "Rx reorder table memory allocation" "failed\n");
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) new_node);
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MDAT_D, "Create ReorderPtr: %p\n", new_node);
+ new_node->timer_context.ptr = new_node;
+ new_node->timer_context.priv = priv;
+ new_node->timer_context.timer_is_set = MFALSE;
+ new_node->ba_status = BA_STREAM_SETUP_INPROGRESS;
+
+ pmadapter->callbacks.moal_init_timer(pmadapter->pmoal_handle,
+ &new_node->timer_context.timer,
+ wlan_flush_data,
+ &new_node->timer_context);
+
+ for (i = 0; i < win_size; ++i)
+ new_node->rx_reorder_ptr[i] = MNULL;
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list) new_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function will return the pointer to a entry in rx reordering
+ * table which matches the give TA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ *
+ * @return A pointer to structure RxReorderTbl
+ */
+RxReorderTbl *
+wlan_11n_get_rxreorder_tbl(mlan_private * priv, int tid, t_u8 * ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ (RxReorderTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ if ((!memcmp
+ (priv->adapter, rx_reor_tbl_ptr->ta, ta, MLAN_MAC_ADDR_LENGTH)) &&
+ (rx_reor_tbl_ptr->tid == tid)) {
+ LEAVE();
+ return rx_reor_tbl_ptr;
+ }
+
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, t_void * pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_REQ *padd_ba_req = (HostCmd_DS_11N_ADDBA_REQ *)
+ & cmd->params.add_ba_req;
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_REQ) + S_DS_GEN);
+
+ memcpy(priv->adapter, padd_ba_req, pdata_buf,
+ sizeof(HostCmd_DS_11N_ADDBA_REQ));
+ padd_ba_req->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_req->block_ack_param_set);
+ padd_ba_req->block_ack_tmo = wlan_cpu_to_le16(padd_ba_req->block_ack_tmo);
+ padd_ba_req->ssn = wlan_cpu_to_le16(padd_ba_req->ssn);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * response.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_addba_rspgen(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
+ & cmd->params.add_ba_rsp;
+ HostCmd_DS_11N_ADDBA_REQ *pevt_addba_req =
+ (HostCmd_DS_11N_ADDBA_REQ *) pdata_buf;
+ t_u8 tid = 0;
+ int win_size = 0;
+
+ ENTER();
+
+ pevt_addba_req->block_ack_param_set =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_param_set);
+ pevt_addba_req->block_ack_tmo =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_tmo);
+ pevt_addba_req->ssn = wlan_le16_to_cpu(pevt_addba_req->ssn);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_RSP) + S_DS_GEN);
+
+ memcpy(priv->adapter, padd_ba_rsp->peer_mac_addr,
+ pevt_addba_req->peer_mac_addr, MLAN_MAC_ADDR_LENGTH);
+ padd_ba_rsp->dialog_token = pevt_addba_req->dialog_token;
+ padd_ba_rsp->block_ack_tmo =
+ wlan_cpu_to_le16(pevt_addba_req->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_cpu_to_le16(pevt_addba_req->ssn);
+
+ padd_ba_rsp->block_ack_param_set = pevt_addba_req->block_ack_param_set;
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (priv->addba_reject[tid]
+#ifdef STA_SUPPORT
+ || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ && priv->wps.session_enable)
+#endif
+#ifdef UAP_SUPPORT
+ || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ && (priv->adapter->pending_bridge_pkts > RX_LOW_THRESHOLD))
+#endif
+ )
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
+ else
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_WINSIZE_MASK;
+ if (!priv->add_ba_param.rx_amsdu ||
+ (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
+ /* We do not support AMSDU inside AMPDU, hence reset the bit */
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+
+ padd_ba_rsp->block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
+ BLOCKACKPARAM_WINSIZE_POS);
+ win_size = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS;
+ if (win_size == 0)
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
+
+ padd_ba_rsp->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
+
+ if (padd_ba_rsp->status_code == wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT))
+ wlan_11n_create_rxreorder_tbl(priv, pevt_addba_req->peer_mac_addr, tid,
+ win_size, pevt_addba_req->ssn);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for deleting a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_delba(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)
+ & cmd->params.del_ba;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_DELBA);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_DELBA) + S_DS_GEN);
+
+ memcpy(priv->adapter, pdel_ba, pdata_buf, sizeof(HostCmd_DS_11N_DELBA));
+ pdel_ba->del_ba_param_set = wlan_cpu_to_le16(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_cpu_to_le16(pdel_ba->reason_code);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will identify if RxReodering is needed for the packet
+ * and will do the reordering if required before sending it to kernel
+ *
+ * @param priv A pointer to mlan_private
+ * @param seq_num Seqence number of the current packet
+ * @param tid Tid of the current packet
+ * @param ta Transmiter address of the current packet
+ * @param pkt_type Packetype for the current packet (to identify if its a BAR)
+ * @param payload Pointer to the payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_11n_rxreorder_pkt(void *priv, t_u16 seq_num, t_u16 tid,
+ t_u8 * ta, t_u8 pkt_type, void *payload)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ int prev_start_win, start_win, end_win, win_size;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = ((mlan_private *) priv)->adapter;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl((mlan_private *) priv, tid, ta))) {
+ if (pkt_type != PKT_TYPE_BAR)
+ wlan_11n_dispatch_pkt(priv, payload);
+
+ LEAVE();
+ return ret;
+
+ } else {
+ if ((pkt_type == PKT_TYPE_AMSDU) && !rx_reor_tbl_ptr->amsdu) {
+ wlan_11n_dispatch_pkt(priv, payload);
+ LEAVE();
+ return ret;
+ }
+ if (pkt_type == PKT_TYPE_BAR)
+ PRINTM(MDAT_D, "BAR ");
+ if (pkt_type == PKT_TYPE_AMSDU)
+ PRINTM(MDAT_D, "AMSDU ");
+
+ prev_start_win = start_win = rx_reor_tbl_ptr->start_win;
+ win_size = rx_reor_tbl_ptr->win_size;
+ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D,
+ "TID %d, TA %02x:%02x:%02x:%02x:%02x:%02x\n",
+ tid, ta[0], ta[1], ta[2], ta[3], ta[4], ta[5]);
+ PRINTM(MDAT_D,
+ "1:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+ /*
+ * If seq_num is less then starting win then ignore and drop
+ * the packet
+ */
+ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { /* Wrap */
+ if (seq_num >= ((start_win + (TWOPOW11)) &
+ (MAX_TID_VALUE - 1)) && (seq_num < start_win)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else if ((seq_num < start_win) ||
+ (seq_num > (start_win + (TWOPOW11)))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * If this packet is a BAR we adjust seq_num as
+ * WinStart = seq_num
+ */
+ if (pkt_type == PKT_TYPE_BAR)
+ seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D,
+ "2:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+
+ if (((end_win < start_win) &&
+ (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) &&
+ (seq_num > end_win))
+ || ((end_win > start_win) &&
+ ((seq_num > end_win) || (seq_num < start_win)))) {
+
+ end_win = seq_num;
+ if (((seq_num - win_size) + 1) >= 0)
+ start_win = (end_win - win_size) + 1;
+ else
+ start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
+
+ if ((ret = wlan_11n_dispatch_pkt_until_start_win(priv,
+ rx_reor_tbl_ptr,
+ start_win))) {
+ goto done;
+ }
+ }
+
+ PRINTM(MDAT_D, "3:seq_num %d start_win %d win_size %d"
+ " end_win %d\n", seq_num, start_win, win_size, end_win);
+ if (pkt_type != PKT_TYPE_BAR) {
+ if (seq_num >= start_win) {
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[seq_num - start_win]) {
+ PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_reor_tbl_ptr->rx_reorder_ptr[seq_num - start_win] = payload;
+ } else { /* Wrap condition */
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+ + (MAX_TID_VALUE)) -
+ start_win]) {
+ PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+ + (MAX_TID_VALUE)) -
+ start_win] = payload;
+ }
+ }
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+
+ /*
+ * Dispatch all packets sequentially from start_win until a
+ * hole is found and adjust the start_win appropriately
+ */
+ ret = wlan_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+ }
+
+ done:
+ if (!rx_reor_tbl_ptr->timer_context.timer_is_set ||
+ (prev_start_win != rx_reor_tbl_ptr->start_win)) {
+
+ mlan_11n_rxreorder_timer_restart(pmadapter, rx_reor_tbl_ptr);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete an entry for a given tid/ta pair. tid/ta
+ * are taken from delba_event body
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid to send delba
+ * @param peer_mac MAC address to send delba
+ * @param type TYPE_DELBA_SENT or TYPE_DELBA_RECEIVE
+ * @param initiator MTRUE if we are initiator of ADDBA, MFALSE otherwise
+ *
+ * @return N/A
+ */
+void
+mlan_11n_delete_bastream_tbl(mlan_private * priv, int tid,
+ t_u8 * peer_mac, t_u8 type, int initiator)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ TxBAStreamTbl *ptxtbl;
+ t_u8 cleanup_rx_reorder_tbl;
+
+ ENTER();
+
+ if (type == TYPE_DELBA_RECEIVE)
+ cleanup_rx_reorder_tbl = (initiator) ? MTRUE : MFALSE;
+ else
+ cleanup_rx_reorder_tbl = (initiator) ? MFALSE : MTRUE;
+
+ PRINTM(MEVENT, "DELBA: %02x:%02x:%02x:%02x:%02x:%02x tid=%d,"
+ "initiator=%d\n", peer_mac[0],
+ peer_mac[1], peer_mac[2],
+ peer_mac[3], peer_mac[4], peer_mac[5], tid, initiator);
+
+ if (cleanup_rx_reorder_tbl) {
+ if (!(rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid,
+ peer_mac))) {
+ PRINTM(MWARN, "TID, TA not found in table!\n");
+ LEAVE();
+ return;
+ }
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ } else {
+ if (!(ptxtbl = wlan_11n_get_txbastream_tbl(priv, tid, peer_mac))) {
+ PRINTM(MWARN, "TID, RA not found in table!\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptxtbl);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of
+ * a block ack response
+ *
+ * @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_resp(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
+ & resp->params.add_ba_rsp;
+ int tid;
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+
+ ENTER();
+
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+ 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);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ /* Check if we had rejected the ADDBA, if yes then do not create the stream */
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ PRINTM(MCMND,
+ "ADDBA RSP: %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);
+
+ if ((rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tid,
+ padd_ba_rsp->peer_mac_addr))) {
+ rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_COMPLETE;
+ if ((padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.rx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ rx_reor_tbl_ptr->amsdu = MTRUE;
+ else
+ rx_reor_tbl_ptr->amsdu = MFALSE;
+ }
+ } else {
+ PRINTM(MERROR,
+ "ADDBA RSP: Failed(%02x:%02x:%02x:%02x:%02x:%02x tid=%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);
+ if ((rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tid,
+ padd_ba_rsp->peer_mac_addr))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles ba_stream_timeout event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event A pointer to structure HostCmd_DS_11N_BATIMEOUT
+ *
+ * @return N/A
+ */
+void
+wlan_11n_ba_stream_timeout(mlan_private * priv,
+ HostCmd_DS_11N_BATIMEOUT * event)
+{
+ HostCmd_DS_11N_DELBA delba;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Event:", (t_u8 *) event, 20);
+
+ memset(priv->adapter, &delba, 0, sizeof(HostCmd_DS_11N_DELBA));
+ memcpy(priv->adapter, delba.peer_mac_addr, event->peer_mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ delba.del_ba_param_set |= (t_u16) event->tid << DELBA_TID_POS;
+ delba.del_ba_param_set |= (t_u16) event->origninator << DELBA_INITIATOR_POS;
+ delba.reason_code = REASON_CODE_STA_TIMEOUT;
+ wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, MNULL, &delba);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function cleans up reorder tbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_cleanup_reorder_tbl(mlan_private * priv)
+{
+ RxReorderTbl *del_tbl_ptr;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (RxReorderTbl *)
+ util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list) & priv->rx_reorder_tbl_ptr);
+
+ memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+ LEAVE();
+}
+
+/**
+ * @brief This function handle the rxba_sync event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event_buf A pointer to event buf
+ * @param len event_buf length
+ * @return N/A
+ */
+void
+wlan_11n_rxba_sync_event(mlan_private * priv, t_u8 * event_buf, t_u16 len)
+{
+ MrvlIEtypes_RxBaSync_t *tlv_rxba = (MrvlIEtypes_RxBaSync_t *) event_buf;
+ t_u16 tlv_type, tlv_len;
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+ t_u8 i, j;
+ t_u16 seq_num = 0;
+ int tlv_buf_left = len;
+ ENTER();
+ DBG_HEXDUMP(MEVT_D, "RXBA_SYNC_EVT", event_buf, len);
+ while (tlv_buf_left >= sizeof(MrvlIEtypes_RxBaSync_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv_rxba->header.type);
+ tlv_len = wlan_le16_to_cpu(tlv_rxba->header.len);
+ if (tlv_type != TLV_TYPE_RXBA_SYNC) {
+ PRINTM(MERROR, "Wrong TLV id=0x%x\n", tlv_type);
+ goto done;
+ }
+ tlv_rxba->seq_num = wlan_le16_to_cpu(tlv_rxba->seq_num);
+ tlv_rxba->bitmap_len = wlan_le16_to_cpu(tlv_rxba->bitmap_len);
+ PRINTM(MEVENT,
+ "%02x:%02x:%02x:%02x:%02x:%02x tid=%d seq_num=%d bitmap_len=%d\n",
+ tlv_rxba->mac[0], tlv_rxba->mac[1], tlv_rxba->mac[2],
+ tlv_rxba->mac[3], tlv_rxba->mac[4], tlv_rxba->mac[5],
+ tlv_rxba->tid, tlv_rxba->seq_num, tlv_rxba->bitmap_len);
+ rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tlv_rxba->tid, tlv_rxba->mac);
+ if (!rx_reor_tbl_ptr) {
+ PRINTM(MEVENT, "Can not find rx_reorder_tbl\n");
+ goto done;
+ }
+ for (i = 0; i < tlv_rxba->bitmap_len; i++) {
+ for (j = 0; j < 8; j++) {
+ if (tlv_rxba->bitmap[i] & (1 << j)) {
+ seq_num =
+ (tlv_rxba->seq_num + i * 8 + j) & (MAX_TID_VALUE - 1);
+ PRINTM(MEVENT,
+ "Fw dropped packet, seq=%d start_win=%d, win_size=%d\n",
+ seq_num, rx_reor_tbl_ptr->start_win,
+ rx_reor_tbl_ptr->win_size);
+ if (MLAN_STATUS_SUCCESS !=
+ mlan_11n_rxreorder_pkt(priv, seq_num, tlv_rxba->tid,
+ tlv_rxba->mac, 0,
+ (t_void *) RX_PKT_DROPPED_IN_FW))
+ {
+ PRINTM(MERROR,
+ "Fail to handle dropped packet, seq=%d\n",
+ seq_num);
+ }
+ }
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv_rxba =
+ (MrvlIEtypes_RxBaSync_t *) ((t_u8 *) tlv_rxba + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will send a DELBA for each entry in the priv's
+ * rx reordering table
+ *
+ * @param priv A pointer to mlan_private
+ */
+t_void
+wlan_send_delba_to_all_in_reorder_tbl(pmlan_private priv)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ (RxReorderTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ if (rx_reor_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE) {
+ rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_INPROGRESS;
+ wlan_send_delba(priv, rx_reor_tbl_ptr->tid, rx_reor_tbl_ptr->ta, 0);
+ }
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function cleans up reorder tbl for specific station
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @return N/A
+ */
+void
+wlan_cleanup_reorder_tbl(mlan_private * priv, t_u8 * ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+ t_u8 i;
+ ENTER();
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ if ((rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, i, ta))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ }
+ }
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h
new file mode 100644
index 000000000000..4ff15834c8a3
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h
@@ -0,0 +1,102 @@
+/** @file mlan_11n_rxreorder.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n RxReordering functionalities
+ *
+ * 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
+********************************************************/
+
+#ifndef _MLAN_11N_RXREORDER_H_
+#define _MLAN_11N_RXREORDER_H_
+
+/** Max value a TID can take = 2^12 = 4096 */
+#define MAX_TID_VALUE (2 << 11)
+/** 2^11 = 2048 */
+#define TWOPOW11 (2 << 10)
+
+/** Tid Mask used for extracting TID from BlockAckParamSet */
+#define BLOCKACKPARAM_TID_MASK 0x3C
+/** Tid position in BlockAckParamSet */
+#define BLOCKACKPARAM_TID_POS 2
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_MASK 0xffc0
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
+/** WinSize position in BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_POS 6
+/** Position of TID in DelBA Param set */
+#define DELBA_TID_POS 12
+/** Position of INITIATOR in DelBA Param set */
+#define DELBA_INITIATOR_POS 11
+/** Reason code: Requested from peer STA as it does not want to use the mechanism */
+#define REASON_CODE_STA_DONT_WANT 37
+/** Reason code: Requested from peer STA due to timeout*/
+#define REASON_CODE_STA_TIMEOUT 39
+/** Type: send delba command */
+#define TYPE_DELBA_SENT 1
+/** Type: recieve delba command */
+#define TYPE_DELBA_RECEIVE 2
+/** Set Initiator Bit */
+#define DELBA_INITIATOR(paramset) (paramset = (paramset | (1 << 11)))
+/** Reset Initiator Bit for recipient */
+#define DELBA_RECIPIENT(paramset) (paramset = (paramset & ~(1 << 11)))
+/** Immediate block ack */
+#define IMMEDIATE_BLOCK_ACK 0x2
+
+/** The request has been declined */
+#define ADDBA_RSP_STATUS_DECLINED 37
+/** ADDBA response status : Reject */
+#define ADDBA_RSP_STATUS_REJECT 1
+/** ADDBA response status : Accept */
+#define ADDBA_RSP_STATUS_ACCEPT 0
+
+/** DEFAULT SEQ NUM */
+#define DEFAULT_SEQ_NUM 0xffff
+
+/** Indicate packet has been dropped in FW */
+#define RX_PKT_DROPPED_IN_FW 0xffffffff
+
+mlan_status mlan_11n_rxreorder_pkt(void *priv, t_u16 seqNum, t_u16 tid,
+ t_u8 * ta, t_u8 pkttype, void *payload);
+void mlan_11n_delete_bastream_tbl(mlan_private * priv, int Tid,
+ t_u8 * PeerMACAddr, t_u8 type, int initiator);
+void wlan_11n_ba_stream_timeout(mlan_private * priv,
+ HostCmd_DS_11N_BATIMEOUT * event);
+mlan_status wlan_ret_11n_addba_resp(mlan_private * priv,
+ HostCmd_DS_COMMAND * resp);
+mlan_status wlan_cmd_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_rspgen(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf);
+void wlan_11n_cleanup_reorder_tbl(mlan_private * priv);
+RxReorderTbl *wlan_11n_get_rxreorder_tbl(mlan_private * priv, int tid,
+ t_u8 * ta);
+void wlan_11n_rxba_sync_event(mlan_private * priv, t_u8 * event_buf, t_u16 len);
+
+/** send delba for all entries in reorder_tbl */
+t_void wlan_send_delba_to_all_in_reorder_tbl(pmlan_private priv);
+
+/** clean up reorder_tbl */
+void wlan_cleanup_reorder_tbl(mlan_private * priv, t_u8 * ta);
+#endif /* _MLAN_11N_RXREORDER_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_cfp.c b/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
new file mode 100644
index 000000000000..ccbb5aa1f666
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
@@ -0,0 +1,1378 @@
+/**
+ * @file mlan_cfp.c
+ *
+ * @brief This file contains WLAN client mode channel, frequency and power
+ * related code
+ *
+ * Copyright (C) 2009-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:
+ 04/16/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_join.h"
+#include "mlan_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** 100mW */
+#define WLAN_TX_PWR_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_US_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_JP_BG_DEFAULT 20
+/** 200mW */
+#define WLAN_TX_PWR_JP_A_DEFAULT 23
+/** 100mW */
+#define WLAN_TX_PWR_FR_100MW 20
+/** 10mW */
+#define WLAN_TX_PWR_FR_10MW 10
+/** 100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT 20
+/** 2000mW */
+#define WLAN_TX_PWR_CN_2000MW 33
+
+/** Region code mapping */
+typedef struct _country_code_mapping
+{
+ /** Region */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Code for B/G CFP table */
+ t_u8 cfp_code_bg;
+ /** Code for A CFP table */
+ t_u8 cfp_code_a;
+} country_code_mapping_t;
+
+/** Region code mapping table */
+static country_code_mapping_t country_code_mapping[] = {
+ {"US", 0x10, 0x10}, /* US FCC */
+ {"CA", 0x10, 0x20}, /* IC Canada */
+ {"SG", 0x10, 0x10}, /* Singapore */
+ {"EU", 0x30, 0x30}, /* ETSI */
+ {"AU", 0x30, 0x30}, /* Australia */
+ {"KR", 0x30, 0x30}, /* Republic Of Korea */
+ {"FR", 0x32, 0x32}, /* France */
+ {"JP", 0xFF, 0x40}, /* Japan */
+ {"CN", 0x30, 0x50}, /* China */
+};
+
+/**
+ * The structure for Channel-Frequency-Power table
+ */
+typedef struct _cfp_table
+{
+ /** Region or Code */
+ t_u8 code;
+ /** Frequency/Power */
+ chan_freq_power_t *cfp;
+ /** No of CFP flag */
+ int cfp_no;
+} cfp_table_t;
+
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/** Band: 'B/G', Region: USA FCC/Canada IC */
+static chan_freq_power_t channel_freq_power_US_BG[] = {
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT, MFALSE}
+};
+
+/** Band: 'B/G', Region: Europe ETSI/China */
+static chan_freq_power_t channel_freq_power_EU_BG[] = {
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE}
+};
+
+/** Band: 'B/G', Region: France */
+static chan_freq_power_t channel_freq_power_FR_BG[] = {
+ {1, 2412, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {2, 2417, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {3, 2422, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {4, 2427, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {5, 2432, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {6, 2437, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {7, 2442, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {8, 2447, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {9, 2452, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {10, 2457, WLAN_TX_PWR_FR_10MW, MFALSE},
+ {11, 2462, WLAN_TX_PWR_FR_10MW, MFALSE},
+ {12, 2467, WLAN_TX_PWR_FR_10MW, MFALSE},
+ {13, 2472, WLAN_TX_PWR_FR_10MW, MFALSE}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN41_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN40_BG[] = {
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPNFE_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MTRUE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MTRUE}
+};
+
+/** Band : 'B/G', Region: Special */
+static chan_freq_power_t channel_freq_power_SPECIAL_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}
+};
+
+/**
+ * The 2.4GHz CFP tables
+ */
+static cfp_table_t cfp_table_BG[] = {
+ {0x10, /* US FCC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x20, /* CANADA IC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x30, /* EU */
+ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x32, /* FRANCE */
+ channel_freq_power_FR_BG,
+ sizeof(channel_freq_power_FR_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x40, /* JAPAN */
+ channel_freq_power_JPN40_BG,
+ sizeof(channel_freq_power_JPN40_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x41, /* JAPAN */
+ channel_freq_power_JPN41_BG,
+ sizeof(channel_freq_power_JPN41_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x50, /* China */
+ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {
+ 0xfe, /* JAPAN */
+ channel_freq_power_JPNFE_BG,
+ sizeof(channel_freq_power_JPNFE_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0xff, /* Special */
+ channel_freq_power_SPECIAL_BG,
+ sizeof(channel_freq_power_SPECIAL_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+/* Add new region here */
+};
+
+/** Number of the CFP tables for 2.4GHz */
+#define MLAN_CFP_TABLE_SIZE_BG (sizeof(cfp_table_BG)/sizeof(cfp_table_t))
+
+/* Format { Channel, Frequency (MHz), MaxTxPower, DFS } */
+/** Band: 'A', Region: USA FCC, Spain, France */
+static chan_freq_power_t channel_freq_power_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT, MFALSE}
+};
+
+/** Band: 'A', Region: Canada IC */
+static chan_freq_power_t channel_freq_power_CAN_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT, MFALSE}
+};
+
+/** Band: 'A', Region: Europe ETSI */
+static chan_freq_power_t channel_freq_power_EU_A[] = {
+ {36, 5180, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE}
+};
+
+/** Band: 'A', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN_A[] = {
+ {8, 5040, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {12, 5060, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {16, 5080, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {36, 5180, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE}
+};
+
+/** Band: 'A', Region: China */
+static chan_freq_power_t channel_freq_power_CN_A[] = {
+ {149, 5745, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {153, 5765, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {157, 5785, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {161, 5805, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {165, 5825, WLAN_TX_PWR_CN_2000MW, MFALSE}
+};
+
+/** Band: 'A', NULL */
+static chan_freq_power_t channel_freq_power_NULL_A[] = {
+};
+
+/** Band: 'A', Code: 1, Low band (5150-5250 MHz) channels */
+static chan_freq_power_t channel_freq_power_low_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+};
+
+/** Band: 'A', Code: 2, Lower middle band (5250-5350 MHz) channels */
+static chan_freq_power_t channel_freq_power_lower_middle_band[] = {
+ {52, 5260, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_DEFAULT, MTRUE},
+};
+
+/** Band: 'A', Code: 3, Upper middle band (5470-5725 MHz) channels */
+static chan_freq_power_t channel_freq_power_upper_middle_band[] = {
+ {100, 5500, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_DEFAULT, MTRUE},
+};
+
+/** Band: 'A', Code: 4, High band (5725-5850 MHz) channels */
+static chan_freq_power_t channel_freq_power_high_band[] = {
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}
+};
+
+/** Band: 'A', Code: 5, Low band (5150-5250 MHz) and
+ * High band (5725-5850 MHz) channels */
+static chan_freq_power_t channel_freq_power_low_high_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}
+};
+
+/**
+ * The 5GHz CFP tables
+ */
+static cfp_table_t cfp_table_A[] = {
+ {0x10, /* US FCC */
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x20, /* CANADA IC */
+ channel_freq_power_CAN_A,
+ sizeof(channel_freq_power_CAN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x30, /* EU */
+ channel_freq_power_EU_A,
+ sizeof(channel_freq_power_EU_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x32, /* FRANCE */
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x40, /* JAPAN */
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x41, /* JAPAN */
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x50, /* China */
+ channel_freq_power_CN_A,
+ sizeof(channel_freq_power_CN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0xfe, /* JAPAN */
+ channel_freq_power_NULL_A,
+ sizeof(channel_freq_power_NULL_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0xff, /* Special */
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x1, /* Low band (5150-5250 MHz) channels */
+ channel_freq_power_low_band,
+ sizeof(channel_freq_power_low_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x2, /* Lower middle band (5250-5350 MHz) channels */
+ channel_freq_power_lower_middle_band,
+ sizeof(channel_freq_power_lower_middle_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x3, /* Upper middle band (5470-5725 MHz) channels */
+ channel_freq_power_upper_middle_band,
+ sizeof(channel_freq_power_upper_middle_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x4, /* High band (5725-5850 MHz) channels */
+ channel_freq_power_high_band,
+ sizeof(channel_freq_power_high_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x5, /* Low band (5150-5250 MHz) and High band
+ (5725-5850 MHz) channels */
+ channel_freq_power_low_high_band,
+ sizeof(channel_freq_power_low_high_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+/* Add new region here */
+};
+
+/** Number of the CFP tables for 5GHz */
+#define MLAN_CFP_TABLE_SIZE_A (sizeof(cfp_table_A)/sizeof(cfp_table_t))
+
+/********************************************************
+ Global Variables
+********************************************************/
+/**
+ * The table to keep region code
+ */
+t_u16 region_code_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0x50, 0xfe, 0xff };
+
+/** The table to keep CFP code for BG */
+t_u16 cfp_code_index_bg[MRVDRV_MAX_CFP_CODE_BG] = { };
+
+/** The table to keep CFP code for A */
+t_u16 cfp_code_index_a[MRVDRV_MAX_CFP_CODE_A] = { 0x1, 0x2, 0x3, 0x4, 0x5 };
+
+/**
+ * The rates supported for ad-hoc B mode
+ */
+t_u8 AdhocRates_B[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
+
+/**
+ * The rates supported for ad-hoc G mode
+ */
+t_u8 AdhocRates_G[G_SUPPORTED_RATES] =
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported for ad-hoc BG mode
+ */
+t_u8 AdhocRates_BG[BG_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0
+};
+
+/**
+ * The rates supported in A mode for ad-hoc
+ */
+t_u8 AdhocRates_A[A_SUPPORTED_RATES] =
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported in A mode (used for BAND_A)
+ */
+t_u8 SupportedRates_A[A_SUPPORTED_RATES] =
+ { 0x0c, 0x12, 0x18, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported by the card
+ */
+t_u16 WlanDataRates[WLAN_SUPPORTED_RATES_EXT] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
+ 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75,
+ 0x82, 0x0C, 0x1B, 0x36, 0x51, 0x6C, 0xA2,
+ 0xD8, 0xF3, 0x10E, 0x00
+};
+
+/**
+ * The rates supported in B mode
+ */
+t_u8 SupportedRates_B[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
+
+/**
+ * The rates supported in G mode (BAND_G, BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_G[G_SUPPORTED_RATES] =
+ { 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported in BG mode (BAND_B|BAND_G, BAND_B|BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_BG[BG_SUPPORTED_RATES] =
+ { 0x02, 0x04, 0x0b, 0x0c, 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0
+};
+
+/**
+ * The rates supported in N mode
+ */
+t_u8 SupportedRates_N[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Find a character in a string.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to string
+ * @param c Character to be located
+ * @param n The length of string
+ *
+ * @return A pointer to the first occurrence of c in string, or MNULL if c is not found.
+ */
+static void *
+wlan_memchr(pmlan_adapter pmadapter, void *s, int c, int n)
+{
+ const t_u8 *p = (t_u8 *) s;
+
+ ENTER();
+
+ while (n--) {
+ if ((t_u8) c == *p++) {
+ LEAVE();
+ return (void *) (p - 1);
+ }
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function finds the CFP in
+ * cfp_table_BG/A based on region/code and band parameter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ *
+ * @return A pointer to CFP
+ */
+static chan_freq_power_t *
+wlan_get_region_cfp_table(pmlan_adapter pmadapter, t_u8 region, t_u8 band,
+ int *cfp_no)
+{
+ t_u32 i;
+ t_u8 cfp_bg, cfp_a;
+
+ ENTER();
+
+ cfp_bg = cfp_a = region;
+ if (!region) {
+ /* Invalid region code, use CFP code */
+ cfp_bg = pmadapter->cfp_code_bg;
+ cfp_a = pmadapter->cfp_code_a;
+ }
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ PRINTM(MINFO, "cfp_table_BG[%d].code=%d\n", i,
+ cfp_table_BG[i].code);
+ /* Check if region/code matches for BG bands */
+ if (cfp_table_BG[i].code == cfp_bg) {
+ /* Select by band */
+ *cfp_no = cfp_table_BG[i].cfp_no;
+ LEAVE();
+ return cfp_table_BG[i].cfp;
+ }
+ }
+ }
+ if (band & (BAND_A | BAND_AN)) {
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ PRINTM(MINFO, "cfp_table_A[%d].code=%d\n", i, cfp_table_A[i].code);
+ /* Check if region/code matches for A bands */
+ if (cfp_table_A[i].code == cfp_a) {
+ /* Select by band */
+ *cfp_no = cfp_table_A[i].cfp_no;
+ LEAVE();
+ return cfp_table_A[i].cfp;
+ }
+ }
+ }
+
+ if (!region)
+ PRINTM(MERROR, "Error Band[0x%x] or code[BG:%#x, A:%#x]\n",
+ band, cfp_bg, cfp_a);
+ else
+ PRINTM(MERROR, "Error Band[0x%x] or region[%#x]\n", band, region);
+
+ LEAVE();
+ return MNULL;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function converts region string to integer code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param country_code Country string
+ * @param cfp_bg Pointer to buffer
+ * @param cfp_a Pointer to buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_misc_country_2_cfp_table_code(pmlan_adapter pmadapter, t_u8 * country_code,
+ t_u8 * cfp_bg, t_u8 * cfp_a)
+{
+ t_u8 i;
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < NELEMENTS(country_code_mapping); i++) {
+ if (!memcmp(pmadapter, country_code_mapping[i].country_code,
+ country_code, COUNTRY_CODE_LEN - 1)) {
+ *cfp_bg = country_code_mapping[i].cfp_code_bg;
+ *cfp_a = country_code_mapping[i].cfp_code_a;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Use index to get the data rate
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param index The index of data rate
+ * @param ht_info ht info
+ *
+ * @return Data rate or 0
+ */
+
+t_u32
+wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index, t_u8 ht_info)
+{
+#define MCS_NUM_SUPP 16
+ t_u16 mcs_rate[4][MCS_NUM_SUPP] =
+ { {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e, 0x36, 0x6c, 0xa2,
+ 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c}
+ , /* LG 40M */
+ {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c, 0x3c, 0x78, 0xb4, 0xf0,
+ 0x168, 0x1e0, 0x21c, 0x258}
+ , /* SG 40M */
+ {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82, 0x1a, 0x34, 0x4e, 0x68,
+ 0x9c, 0xd0, 0xea, 0x104}
+ , /* LG 20M */
+ {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90, 0x1c, 0x39, 0x56, 0x73,
+ 0xad, 0xe7, 0x104, 0x120}
+ }; /* SG 20M */
+
+ t_u32 rate = 0;
+ ENTER();
+
+ if (ht_info & MBIT(0)) {
+ if (index == MLAN_RATE_BITMAP_MCS0) {
+ if (ht_info & MBIT(2))
+ rate = 0x0D; /* MCS 32 SGI rate */
+ else
+ rate = 0x0C; /* MCS 32 LGI rate */
+ } else if (index < MCS_NUM_SUPP) {
+ if (ht_info & MBIT(1)) {
+ if (ht_info & MBIT(2))
+ rate = mcs_rate[1][index]; /* SGI, 40M */
+ else
+ rate = mcs_rate[0][index]; /* LGI, 40M */
+ } else {
+ if (ht_info & MBIT(2))
+ rate = mcs_rate[3][index]; /* SGI, 20M */
+ else
+ rate = mcs_rate[2][index]; /* LGI, 20M */
+ }
+ } else
+ rate = WlanDataRates[0];
+ } else {
+ /* 11n non HT rates */
+ if (index >= WLAN_SUPPORTED_RATES_EXT)
+ index = 0;
+ rate = WlanDataRates[index];
+ }
+ LEAVE();
+ return rate;
+}
+
+/**
+ * @brief Use rate to get the index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate Data rate
+ *
+ * @return Index or 0
+ */
+t_u8
+wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate)
+{
+ t_u16 *ptr;
+
+ ENTER();
+ if (rate)
+ if ((ptr = wlan_memchr(pmadapter, WlanDataRates, (t_u8) rate,
+ sizeof(WlanDataRates)))) {
+ LEAVE();
+ return (t_u8) (ptr - WlanDataRates);
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get active data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_mode The specified BSS mode (Infra/IBSS)
+ * @param config_bands The specified band configuration
+ * @param rates The buf to return the active rates
+ *
+ * @return The number of Rates
+ */
+t_u32
+wlan_get_active_data_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates)
+{
+ t_u32 k;
+
+ ENTER();
+
+ if (pmpriv->media_connected != MTRUE) {
+ k = wlan_get_supported_rates(pmpriv, bss_mode, config_bands, rates);
+ } else {
+ k = wlan_copy_rates(rates, 0, pmpriv->curr_bss_params.data_rates,
+ pmpriv->curr_bss_params.num_of_rates);
+ }
+
+ LEAVE();
+ return k;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function search through all the regions cfp table to find the channel,
+ * if the channel is found then gets the MIN txpower of the channel
+ * present in all the regions.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param channel Channel number.
+ *
+ * @return The Tx power
+ */
+t_u8
+wlan_get_txpwr_of_chan_from_cfp(mlan_private * pmpriv, t_u8 channel)
+{
+ t_u8 i = 0;
+ t_u8 j = 0;
+ t_u8 tx_power = 0;
+ t_u32 cfp_no;
+ chan_freq_power_t *cfp = MNULL;
+ chan_freq_power_t *cfp_a = MNULL;
+ t_u32 cfp_no_a;
+
+ ENTER();
+
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ /* Get CFP */
+ cfp = cfp_table_BG[i].cfp;
+ cfp_no = cfp_table_BG[i].cfp_no;
+ /* Find matching channel and get Tx power */
+ for (j = 0; j < cfp_no; j++) {
+ if ((cfp + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power, (cfp + j)->max_tx_power);
+ else
+ tx_power = (t_u8) (cfp + j)->max_tx_power;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ /* Get CFP */
+ cfp_a = cfp_table_A[i].cfp;
+ cfp_no_a = cfp_table_A[i].cfp_no;
+ for (j = 0; j < cfp_no_a; j++) {
+ if ((cfp_a + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power, (cfp_a + j)->max_tx_power);
+ else
+ tx_power = (t_u8) ((cfp_a + j)->max_tx_power);
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return tx_power;
+}
+
+/**
+ * @brief Get the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ * @param region_channel A pointer to region_chan_t structure
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not found.
+ */
+
+chan_freq_power_t *
+wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u16 channel, region_chan_t * region_channel)
+{
+ region_chan_t *rc;
+ chan_freq_power_t *cfp = MNULL;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = &region_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A: /* Matching BAND_A */
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G:
+ case BAND_B: /* Matching BAND_B/G */
+ case BAND_G:
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ if (channel == FIRST_VALID_CHANNEL)
+ cfp = &rc->pcfp[0];
+ else {
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].channel == channel) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (!cfp && channel)
+ PRINTM(MERROR, "wlan_get_cfp_by_band_and_channel(): cannot find "
+ "cfp by band %d & channel %d\n", band, channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not found.
+ */
+chan_freq_power_t *
+wlan_find_cfp_by_band_and_channel(mlan_adapter * pmadapter,
+ t_u8 band, t_u16 channel)
+{
+ chan_freq_power_t *cfp = MNULL;
+
+ ENTER();
+
+ /* Any station(s) with 11D enabled */
+ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled,
+ wlan_is_station) > 0)
+ cfp = wlan_get_cfp_by_band_and_channel(pmadapter, band, channel,
+ pmadapter->universal_channel);
+ else
+ cfp = wlan_get_cfp_by_band_and_channel(pmadapter, band, channel,
+ pmadapter->region_channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param freq The frequency to search for
+ *
+ * @return Pointer to chan_freq_power_t structure; MNULL if not found
+ */
+chan_freq_power_t *
+wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter, t_u8 band, t_u32 freq)
+{
+ chan_freq_power_t *cfp = MNULL;
+ region_chan_t *rc;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = &pmadapter->region_channel[j];
+
+ /* Any station(s) with 11D enabled */
+ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled,
+ wlan_is_station) > 0)
+ rc = &pmadapter->universal_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A: /* Matching BAND_A */
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G:
+ case BAND_B:
+ case BAND_G:
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].freq == freq) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && freq)
+ PRINTM(MERROR, "wlan_find_cfp_by_band_and_freq(): cannot find cfp by "
+ "band %d & freq %d\n", band, freq);
+
+ LEAVE();
+ return cfp;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Check if Rate Auto
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8
+wlan_is_rate_auto(mlan_private * pmpriv)
+{
+ t_u32 i;
+ int rate_num = 0;
+
+ ENTER();
+
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates); i++)
+ if (pmpriv->bitmap_rates[i])
+ rate_num++;
+
+ LEAVE();
+ if (rate_num > 1)
+ return MTRUE;
+ else
+ return MFALSE;
+}
+
+/**
+ * @brief Covert Rate Bitmap to Rate index
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param rate_bitmap Pointer to rate bitmap
+ * @param size Size of the bitmap array
+ *
+ * @return Rate index
+ */
+int
+wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rate_bitmap, int size)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < size * 8; i++) {
+ if (rate_bitmap[i / 16] & (1 << (i % 16))) {
+ LEAVE();
+ return i;
+ }
+ }
+
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief Get supported data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_mode The specified BSS mode (Infra/IBSS)
+ * @param config_bands The specified band configuration
+ * @param rates The buf to return the supported rates
+ *
+ * @return The number of Rates
+ */
+t_u32
+wlan_get_supported_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates)
+{
+ t_u32 k = 0;
+
+ ENTER();
+
+ if (bss_mode == MLAN_BSS_MODE_INFRA) {
+ /* Infra. mode */
+ switch (config_bands) {
+ case BAND_B:
+ PRINTM(MINFO, "Infra Band=%d SupportedRates_B\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_B,
+ sizeof(SupportedRates_B));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_G\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
+ case BAND_B | BAND_G | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_BG\n", config_bands);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ else
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+#else
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+#endif
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_N\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_N,
+ sizeof(SupportedRates_N));
+ break;
+ }
+ } else {
+ /* Ad-hoc mode */
+ switch (config_bands) {
+ case BAND_B:
+ PRINTM(MINFO, "Band: Adhoc B\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_B, sizeof(AdhocRates_B));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ PRINTM(MINFO, "Band: Adhoc G only\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_G, sizeof(AdhocRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_B | BAND_G | BAND_GN:
+ PRINTM(MINFO, "Band: Adhoc BG\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_BG, sizeof(AdhocRates_BG));
+ break;
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ PRINTM(MINFO, "Band: Adhoc A\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_A, sizeof(AdhocRates_A));
+ break;
+ }
+ }
+
+ LEAVE();
+ return k;
+}
+
+/**
+ * @brief This function sets region table.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param region The region code
+ * @param band The band
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int i = 0;
+ chan_freq_power_t *cfp;
+ int cfp_no;
+
+ ENTER();
+
+ memset(pmadapter, pmadapter->region_channel, 0,
+ sizeof(pmadapter->region_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ cfp =
+ wlan_get_region_cfp_table(pmadapter, region,
+ BAND_G | BAND_B | BAND_GN, &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band B-G\n", region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ if (band & BAND_GN)
+ pmadapter->region_channel[i].band = BAND_G;
+ else
+ pmadapter->region_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+ if (band & (BAND_A | BAND_AN)) {
+ cfp = wlan_get_region_cfp_table(pmadapter, region, BAND_A, &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band A\n", region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ pmadapter->region_channel[i].band = BAND_A;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get if radar detection is enabled or not on a certain channel
+ *
+ * @param priv Private driver information structure
+ * @param chnl Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ */
+t_bool
+wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl)
+{
+ int i, j;
+ t_bool required = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /* get the cfp table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band == BAND_A) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (!pcfp) {
+ /* This means operation in BAND-A is not support, we can just return
+ false here, it's harmless */
+ goto done;
+ }
+
+ /* get the radar detection requirements according to chan num */
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chnl) {
+ required = pcfp[j].passive_scan_or_radar_detect;
+ break;
+ }
+ }
+
+ done:
+ LEAVE();
+ return required;
+}
+
+/**
+ * @brief Get if scan type is passive or not on a certain channel for b/g band
+ *
+ * @param priv Private driver information structure
+ * @param chnl Channel to determine scan type
+ *
+ * @return
+ * - MTRUE if scan type is passive
+ * - MFALSE otherwise
+ */
+
+t_bool
+wlan_bg_scan_type_is_passive(mlan_private * priv, t_u8 chnl)
+{
+ int i, j;
+ t_bool passive = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /* get the cfp table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & (BAND_B | BAND_G)) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (!pcfp) {
+ /* This means operation in BAND-B or BAND_G is not support, we can
+ just return false here */
+ goto done;
+ }
+
+ /* get the bg scan type according to chan num */
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chnl) {
+ passive = pcfp[j].passive_scan_or_radar_detect;
+ break;
+ }
+ }
+
+ done:
+ LEAVE();
+ return passive;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c b/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
new file mode 100644
index 000000000000..a3e5ef0517f0
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
@@ -0,0 +1,2934 @@
+/**
+ * @file mlan_cmdevt.c
+ *
+ * @brief This file contains the handling of CMD/EVENT in MLAN
+ *
+ * Copyright (C) 2009-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:
+ 05/12/2009: initial version
+************************************************************/
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_sdio.h"
+/********************************************************
+ Local Variables
+********************************************************/
+
+/*******************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function convert a given character to hex
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted hex if chr is a valid hex, else 0
+ */
+static t_u32
+wlan_hexval(t_u8 chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+/**
+ * @brief This function convert a given string to hex
+ *
+ * @param a A pointer to string to be converted
+ *
+ * @return The converted hex value if param a is a valid hex, else 0
+ */
+int
+wlan_atox(t_u8 * a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (wlan_isxdigit(*a))
+ i = i * 16 + wlan_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief This function parse cal data from ASCII to hex
+ *
+ * @param src A pointer to source data
+ * @param len Source dara length
+ * @param dst A pointer to a buf to store the parsed data
+ *
+ * @return The parsed hex data length
+ */
+static t_u32
+wlan_parse_cal_cfg(t_u8 * src, t_size len, t_u8 * dst)
+{
+ t_u8 *ptr;
+ t_u8 *dptr;
+
+ ENTER();
+ ptr = src;
+ dptr = dst;
+
+ while (ptr - src < len) {
+ while (*ptr && (wlan_isspace(*ptr) || *ptr == '\t')) {
+ ptr++;
+ }
+
+ if (wlan_isxdigit(*ptr)) {
+ *dptr++ = wlan_atox(ptr);
+ ptr += 2;
+ } else {
+ ptr++;
+ }
+ }
+ LEAVE();
+ return (dptr - dst);
+}
+
+/**
+ * @brief This function initializes the command node.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return N/A
+ */
+static void
+wlan_init_cmd_node(IN pmlan_private pmpriv,
+ IN cmd_ctrl_node * pcmd_node,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->priv = pmpriv;
+ pcmd_node->cmd_oid = cmd_oid;
+ pcmd_node->pioctl_buf = pioctl_buf;
+ pcmd_node->pdata_buf = pdata_buf;
+
+ pcmd_node->cmdbuf = pcmd_node->pmbuf;
+
+ /* Make sure head_ptr for cmd buf is Align */
+ pcmd_node->cmdbuf->data_offset = 0;
+ memset(pmadapter, pcmd_node->cmdbuf->pbuf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ /* Prepare mlan_buffer for command sending */
+ pcmd_node->cmdbuf->buf_type = MLAN_BUF_TYPE_CMD;
+ pcmd_node->cmdbuf->data_offset += INTF_HEADER_LEN;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or MNULL
+ */
+static cmd_ctrl_node *
+wlan_get_cmd_node(mlan_adapter * pmadapter)
+{
+ cmd_ctrl_node *pcmd_node;
+
+ ENTER();
+
+ if (pmadapter == MNULL) {
+ LEAVE();
+ return MNULL;
+ }
+
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ pcmd_node = (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+ } else {
+ PRINTM(MERROR, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ pcmd_node = MNULL;
+ }
+
+ LEAVE();
+ return pcmd_node;
+}
+
+/**
+ * @brief This function cleans command node.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_clean_cmd_node(pmlan_adapter pmadapter, cmd_ctrl_node * pcmd_node)
+{
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->cmd_oid = 0;
+ pcmd_node->cmd_flag = 0;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->pdata_buf = MNULL;
+
+ if (pcmd_node->respbuf) {
+ wlan_free_mlan_buffer(pmadapter, pcmd_node->respbuf);
+ pcmd_node->respbuf = MNULL;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will return the pointer to the first entry in
+ * pending cmd which matches the given pioctl_req
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return A pointer to first entry match pioctl_req
+ */
+static cmd_ctrl_node *
+wlan_get_pending_ioctl_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ if (!
+ (pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+ while (pcmd_node != (cmd_ctrl_node *) & pmadapter->cmd_pending_q) {
+ if (pcmd_node->pioctl_buf == pioctl_req) {
+ LEAVE();
+ return pcmd_node;
+ }
+ pcmd_node = pcmd_node->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function handles the command response of host_cmd
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_host_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc;
+ t_u16 size = wlan_le16_to_cpu(resp->size);
+
+ ENTER();
+
+ PRINTM(MINFO, "host command response size = %d\n", size);
+ size = MIN(size, MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc->param.hostcmd.len = size;
+ memcpy(pmpriv->adapter, misc->param.hostcmd.cmd, (void *) resp, size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends host command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_host_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *) pdata_buf;
+
+ ENTER();
+
+ /* Copy the HOST command to command buffer */
+ memcpy(pmpriv->adapter, (void *) cmd, pcmd_ptr->cmd,
+ MIN(MRVDRV_SIZE_OF_CMD_BUFFER, pcmd_ptr->len));
+ PRINTM(MINFO, "Host command size = %d\n", pcmd_ptr->len);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function downloads a command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
+{
+
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ t_u16 cmd_code;
+ t_u16 cmd_size;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+
+ ENTER();
+
+ if (pcmd_node)
+ if (pcmd_node->pioctl_buf != MNULL)
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ if (!pmadapter || !pcmd_node) {
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+
+ /* Sanity test */
+ if (pcmd == MNULL || pcmd->size == 0) {
+ PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, "
+ "Not sending\n");
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Set command sequence number */
+ pmadapter->seq_num++;
+ pcmd->seq_num =
+ wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
+ (pmadapter->seq_num, pcmd_node->priv->bss_num,
+ pcmd_node->priv->bss_type));
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = pcmd_node;
+ wlan_release_cmd_lock(pmadapter);
+
+ cmd_code = wlan_le16_to_cpu(pcmd->command);
+ cmd_size = wlan_le16_to_cpu(pcmd->size);
+
+ pcmd_node->cmdbuf->data_len = cmd_size;
+
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
+ PRINTM_NETINTF(MCMND, pmpriv);
+ PRINTM(MCMND, "DNLD_CMD (%lu.%06lu): 0x%x, act 0x%x, len %d, seqno 0x%x\n",
+ sec, usec, cmd_code,
+ wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)), cmd_size,
+ wlan_le16_to_cpu(pcmd->seq_num));
+ DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *) pcmd, cmd_size);
+
+ /* Send the command to lower layer */
+
+ pcmd_node->cmdbuf->data_offset -= INTF_HEADER_LEN;
+ pcmd_node->cmdbuf->data_len += INTF_HEADER_LEN;
+ /* Extra header for SDIO is added here */
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pcmd_node->cmdbuf,
+ MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n");
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ pmadapter->dbg.num_cmd_host_to_card_failure++;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the last command id and action to debug log */
+ pmadapter->dbg.last_cmd_index =
+ (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code;
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] =
+ wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN));
+
+ /* Clear BSS_NO_BITS from HostCmd */
+ cmd_code &= HostCmd_CMD_ID_MASK;
+ /* soft_reset command has no command response, we should return here */
+ if (cmd_code == HostCmd_CMD_SOFT_RESET) {
+ PRINTM(MCMND, "DNLD_CMD: SoftReset\n");
+ if (pioctl_buf) {
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_SUCCESS);
+ }
+ goto done;
+ }
+
+ /* Setup the timer after transmit command */
+ pcb->moal_start_timer(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_timer,
+ MFALSE, MRVDRV_TIMER_60S);
+
+ pmadapter->cmd_timer_is_set = MTRUE;
+
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends sleep confirm command to firmware.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_dnld_sleep_confirm_cmd(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ static t_u32 i = 0;
+ t_u16 cmd_len = 0;
+ opt_sleep_confirm_buffer *sleep_cfm_buf =
+ (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset);
+
+ ENTER();
+
+ cmd_len = sizeof(OPT_Confirm_Sleep);
+ pmadapter->seq_num++;
+ sleep_cfm_buf->ps_cfm_sleep.seq_num =
+ wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
+ (pmadapter->seq_num,
+ (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY))->
+ bss_num,
+ (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY))->
+ bss_type));
+ DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep,
+ sizeof(OPT_Confirm_Sleep));
+
+ /* Send sleep confirm command to firmware */
+
+ pmadapter->psleep_cfm->data_len = cmd_len + INTF_HEADER_LEN;
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD,
+ pmadapter->psleep_cfm, MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "SLEEP_CFM: failed\n");
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+ goto done;
+ } else {
+ if (GET_BSS_ROLE(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY)) ==
+ MLAN_BSS_ROLE_UAP)
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY)) ==
+ MLAN_BSS_ROLE_STA) {
+ if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl) {
+ /* Response is not needed for sleep confirm command */
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ } else {
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+ }
+
+ if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl
+ && (pmadapter->is_hs_configured &&
+ !pmadapter->sleep_period.period)) {
+ pmadapter->pm_wakeup_card_req = MTRUE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_STA),
+ MTRUE);
+ }
+ }
+#endif /* STA_SUPPORT */
+
+#define NUM_SC_PER_LINE 16
+ if (++i % NUM_SC_PER_LINE == 0)
+ PRINTM(MEVENT, "+\n");
+ else
+ PRINTM(MEVENT, "+");
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Event handler
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param event_id Event ID
+ * @param pmevent Event buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_recv_event(pmlan_private priv, mlan_event_id event_id, t_void * pmevent)
+{
+ pmlan_callbacks pcb = &priv->adapter->callbacks;
+
+ ENTER();
+
+ if (pmevent)
+ /* The caller has provided the event. */
+ pcb->moal_recv_event(priv->adapter->pmoal_handle,
+ (pmlan_event) pmevent);
+ else {
+ mlan_event mevent;
+
+ memset(priv->adapter, &mevent, 0, sizeof(mlan_event));
+ mevent.bss_index = priv->bss_index;
+ mevent.event_id = event_id;
+ mevent.event_len = 0;
+
+ pcb->moal_recv_event(priv->adapter->pmoal_handle, &mevent);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates the command buffer and links
+ * it to command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array = MNULL;
+ t_u32 buf_size;
+ t_u32 i;
+
+ ENTER();
+
+ /* Allocate and initialize cmd_ctrl_node */
+ buf_size = sizeof(cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & pcmd_array);
+ if (ret != MLAN_STATUS_SUCCESS || !pcmd_array) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate pcmd_array\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->cmd_pool = pcmd_array;
+ memset(pmadapter, pmadapter->cmd_pool, 0, buf_size);
+
+ /* Allocate and initialize command buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (!(pcmd_array[i].pmbuf = wlan_alloc_mlan_buffer(pmadapter,
+ MRVDRV_SIZE_OF_CMD_BUFFER,
+ 0, MTRUE))) {
+ PRINTM(MERROR,
+ "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ wlan_insert_cmd_to_free_q(pmadapter, &pcmd_array[i]);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the command buffer.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_free_cmd_buffer(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array;
+ t_u32 i;
+
+ ENTER();
+
+ /* Need to check if cmd pool is allocated or not */
+ if (pmadapter->cmd_pool == MNULL) {
+ PRINTM(MINFO, "FREE_CMD_BUF: cmd_pool is Null\n");
+ goto done;
+ }
+
+ pcmd_array = pmadapter->cmd_pool;
+
+ /* Release shared memory buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (pcmd_array[i].pmbuf) {
+ PRINTM(MINFO, "Free all the command buffer.\n");
+ wlan_free_mlan_buffer(pmadapter, pcmd_array[i].pmbuf);
+ pcmd_array[i].pmbuf = MNULL;
+ }
+ if (pcmd_array[i].respbuf) {
+ wlan_free_mlan_buffer(pmadapter, pcmd_array[i].respbuf);
+ pcmd_array[i].respbuf = MNULL;
+ }
+ }
+ /* Release cmd_ctrl_node */
+ if (pmadapter->cmd_pool) {
+ PRINTM(MINFO, "Free command pool.\n");
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter->cmd_pool);
+ pmadapter->cmd_pool = MNULL;
+ }
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_event(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u32 eventcause = pmadapter->event_cause;
+#ifdef DEBUG_LEVEL1
+ t_u32 in_ts_sec, in_ts_usec;
+#endif
+ ENTER();
+
+ /* Save the last event to debug log */
+ pmadapter->dbg.last_event_index =
+ (pmadapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_event[pmadapter->dbg.last_event_index] =
+ (t_u16) eventcause;
+
+ if ((eventcause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) {
+ if (wlan_11h_dfs_event_preprocessing(pmadapter) == MLAN_STATUS_SUCCESS) {
+ memcpy(pmadapter, (t_u8 *) & eventcause,
+ pmbuf->pbuf + pmbuf->data_offset, sizeof(eventcause));
+ }
+ }
+ /* Get BSS number and corresponding priv */
+ priv =
+ wlan_get_priv_by_id(pmadapter, EVENT_GET_BSS_NUM(eventcause),
+ EVENT_GET_BSS_TYPE(eventcause));
+ if (!priv)
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+
+ /* Clear BSS_NO_BITS from event */
+ eventcause &= EVENT_ID_MASK;
+ pmadapter->event_cause = eventcause;
+
+ if (pmbuf) {
+ pmbuf->bss_index = priv->bss_index;
+ memcpy(pmadapter,
+ pmbuf->pbuf + pmbuf->data_offset,
+ (t_u8 *) & eventcause, sizeof(eventcause));
+ }
+
+ if (MTRUE && (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE)
+ ) {
+ PRINTM_GET_SYS_TIME(MEVENT, &in_ts_sec, &in_ts_usec);
+ PRINTM_NETINTF(MEVENT, priv);
+ PRINTM(MEVENT, "%lu.%06lu : Event: 0x%x\n", in_ts_sec, in_ts_usec,
+ eventcause);
+ }
+
+ ret = priv->ops.process_event(priv);
+
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+ if (pmbuf) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function requests a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_request_cmd_lock(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin lock callback function */
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function releases a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_release_cmd_lock(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin unlock callback function */
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_prepare_cmd(IN mlan_private * pmpriv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_COMMAND *cmd_ptr = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /* Sanity test */
+ if (!pmadapter || pmadapter->surprise_removed) {
+ PRINTM(MERROR, "PREP_CMD: Card is Removed\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->hw_status == WlanHardwareStatusReset) {
+ if ((cmd_no != HostCmd_CMD_FUNC_INIT)
+ ) {
+ PRINTM(MERROR, "PREP_CMD: FW is in reset state\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Get a new command node */
+ pcmd_node = wlan_get_cmd_node(pmadapter);
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd node\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Initialize the command node */
+ wlan_init_cmd_node(pmpriv, pcmd_node, cmd_oid, pioctl_buf, pdata_buf);
+
+ if (pcmd_node->cmdbuf == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd buf\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd_ptr =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ cmd_ptr->command = cmd_no;
+ cmd_ptr->result = 0;
+
+ /* Prepare command */
+ if (cmd_no)
+ ret =
+ pmpriv->ops.prepare_cmd(pmpriv, cmd_no, cmd_action, cmd_oid,
+ pioctl_buf, pdata_buf, cmd_ptr);
+ else {
+ ret = wlan_cmd_host_cmd(pmpriv, cmd_ptr, pdata_buf);
+ pcmd_node->cmd_flag |= CMD_F_HOSTCMD;
+ }
+
+ /* Return error, since the command preparation failed */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send command */
+#ifdef STA_SUPPORT
+ if (cmd_no == HostCmd_CMD_802_11_SCAN
+ || cmd_no == HostCmd_CMD_802_11_SCAN_EXT)
+ wlan_queue_scan_cmd(pmpriv, pcmd_node);
+ else {
+#endif
+ if ((cmd_no == HostCmd_CMD_802_11_HS_CFG_ENH) &&
+ (cmd_action == HostCmd_ACT_GEN_SET) &&
+ (pmadapter->hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL))
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MFALSE);
+ else
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+#ifdef STA_SUPPORT
+ }
+#endif
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function inserts command node to cmd_free_q
+ * after cleaning it.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ if (pcmd_node->pioctl_buf) {
+ pioctl_req = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ if (pioctl_req->status_code != MLAN_ERROR_NO_ERROR)
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req, MLAN_STATUS_FAILURE);
+ else
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req, MLAN_STATUS_SUCCESS);
+ }
+ /* Clean the node */
+ wlan_clean_cmd_node(pmadapter, pcmd_node);
+
+ /* Insert node into cmd_free_q */
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->cmd_free_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function queues the command to cmd list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param add_tail Specify if the cmd needs to be queued in the header or tail
+ *
+ * @return N/A
+ */
+t_void
+wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node, IN t_u32 add_tail)
+{
+ HostCmd_DS_COMMAND *pcmd = MNULL;
+ t_u16 command;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd_node is MNULL\n");
+ goto done;
+ }
+
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ if (pcmd == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd is MNULL\n");
+ goto done;
+ }
+
+ command = wlan_le16_to_cpu(pcmd->command);
+
+ /* Exit_PS command needs to be queued in the header always. */
+ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &pcmd->params.psmode_enh;
+ if (wlan_le16_to_cpu(pm->action) == DIS_AUTO_PS) {
+ if (pmadapter->ps_state != PS_STATE_AWAKE)
+ add_tail = MFALSE;
+ }
+ }
+
+ if (add_tail) {
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ } else {
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ PRINTM_NETINTF(MCMND, pcmd_node->priv);
+ PRINTM(MCMND, "QUEUE_CMD: cmd=0x%x is queued\n", command);
+
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function executes next command in command
+ * pending queue. It will put firmware back to PS mode
+ * if applicable.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_exec_next_cmd(mlan_adapter * pmadapter)
+{
+ mlan_private *priv = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+
+ ENTER();
+
+ /* Sanity test */
+ if (pmadapter == MNULL) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: pmadapter is MNULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Check if already in processing */
+ if (pmadapter->curr_cmd) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: there is command in processing!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ /* Check if any command is pending */
+ pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ if (pcmd_node) {
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ priv = pcmd_node->priv;
+
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ PRINTM(MERROR,
+ "Cannot send command in sleep state, this should not happen\n");
+ wlan_release_cmd_lock(pmadapter);
+ goto done;
+ }
+
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ wlan_release_cmd_lock(pmadapter);
+ ret = wlan_dnld_cmd_to_fw(priv, pcmd_node);
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ /* Any command sent to the firmware when host is in sleep mode, should
+ de-configure host sleep */
+ /* We should skip the host sleep configuration command itself though */
+ if (priv &&
+ (pcmd->command !=
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(priv, MFALSE);
+ }
+ }
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_cmdresp(mlan_adapter * pmadapter)
+{
+ HostCmd_DS_COMMAND *resp = MNULL;
+ mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ mlan_private *pmpriv_next = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 orig_cmdresp_no;
+ t_u16 cmdresp_no;
+ t_u16 cmdresp_result;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+ t_u32 i;
+
+ ENTER();
+
+ /* Now we got response from FW, cancel the command timer */
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ /* Cancel command timeout timer */
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+
+ if (pmadapter->curr_cmd)
+ if (pmadapter->curr_cmd->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ }
+
+ if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) {
+ resp = (HostCmd_DS_COMMAND *) pmadapter->upld_buf;
+ resp->command = wlan_le16_to_cpu(resp->command);
+ PRINTM(MERROR, "CMD_RESP: No curr_cmd, 0x%x\n", resp->command);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->num_cmd_timeout = 0;
+
+ DBG_HEXDUMP(MCMD_D, "CMD_RESP",
+ pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset,
+ pmadapter->curr_cmd->respbuf->data_len);
+
+ resp =
+ (HostCmd_DS_COMMAND *) (pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset);
+ wlan_request_cmd_lock(pmadapter);
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
+ cmd_ctrl_node *free_cmd = pmadapter->curr_cmd;
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ PRINTM(MERROR, "CMD_RESP: 0x%x been canceled!\n",
+ wlan_le16_to_cpu(resp->command));
+ wlan_insert_cmd_to_free_q(pmadapter, free_cmd);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ /* Copy original response back to response buffer */
+ wlan_ret_host_cmd(pmpriv, resp, pioctl_buf);
+ }
+ orig_cmdresp_no = wlan_le16_to_cpu(resp->command);
+ resp->size = wlan_le16_to_cpu(resp->size);
+ resp->seq_num = wlan_le16_to_cpu(resp->seq_num);
+ resp->result = wlan_le16_to_cpu(resp->result);
+
+ /* Get BSS number and corresponding priv */
+ pmpriv =
+ wlan_get_priv_by_id(pmadapter, HostCmd_GET_BSS_NO(resp->seq_num),
+ HostCmd_GET_BSS_TYPE(resp->seq_num));
+ if (!pmpriv)
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ /* Clear RET_BIT from HostCmd */
+ resp->command = (orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+ cmdresp_no = resp->command;
+
+ cmdresp_result = resp->result;
+
+ /* Save the last command response to debug log */
+ pmadapter->dbg.last_cmd_resp_index =
+ (pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
+ orig_cmdresp_no;
+
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
+ PRINTM_NETINTF(MCMND, pmadapter->curr_cmd->priv);
+ PRINTM(MCMND, "CMD_RESP (%lu.%06lu): 0x%x, result %d, len %d, seqno 0x%x\n",
+ sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
+ resp->seq_num);
+
+ if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
+ PRINTM(MERROR, "CMD_RESP: Invalid response to command!\n");
+ if (pioctl_buf) {
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
+ if ((cmdresp_result == HostCmd_RESULT_OK)
+ && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ } else {
+ /* handle response */
+ ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf);
+ }
+
+ /* Check init command response */
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing) {
+ if (ret == MLAN_STATUS_FAILURE) {
+#if defined(STA_SUPPORT)
+ if (pmadapter->pwarm_reset_ioctl_req) {
+ /* warm reset failure */
+ pmadapter->pwarm_reset_ioctl_req->status_code =
+ MLAN_ERROR_CMD_RESP_FAIL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pmadapter->pwarm_reset_ioctl_req,
+ MLAN_STATUS_FAILURE);
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+ goto done;
+ }
+#endif
+ PRINTM(MERROR, "cmd 0x%02x failed during initialization\n",
+ cmdresp_no);
+ wlan_init_fw_complete(pmadapter);
+ goto done;
+ }
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ if (pmadapter->curr_cmd) {
+ cmd_ctrl_node *free_cmd = pmadapter->curr_cmd;
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS))
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+ else if (pioctl_buf && (ret == MLAN_STATUS_FAILURE))
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_insert_cmd_to_free_q(pmadapter, free_cmd);
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+
+ if ((pmadapter->hw_status == WlanHardwareStatusInitializing) &&
+ (pmadapter->last_init_cmd == cmdresp_no)) {
+ i = pmpriv->bss_index + 1;
+ while (!(pmpriv_next = pmadapter->priv[i]) && i < pmadapter->priv_num)
+ i++;
+ if (!pmpriv_next || i >= pmadapter->priv_num) {
+#if defined(STA_SUPPORT)
+ if (pmadapter->pwarm_reset_ioctl_req) {
+ /* warm reset complete */
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pmadapter->pwarm_reset_ioctl_req,
+ MLAN_STATUS_SUCCESS);
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+ goto done;
+ }
+#endif
+ pmadapter->hw_status = WlanHardwareStatusInitdone;
+ } else {
+ /* Issue init commands for the next interface */
+ ret = pmpriv_next->ops.init_cmd(pmpriv_next, MFALSE);
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @param function_context A pointer to function_context
+ * @return N/A
+ */
+t_void
+wlan_cmd_timeout_func(t_void * function_context)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) function_context;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+ t_u8 i;
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+ pmadapter->num_cmd_timeout++;
+ pmadapter->dbg.num_cmd_timeout++;
+ if (!pmadapter->curr_cmd) {
+ PRINTM(MWARN, "CurCmd Empty\n");
+ goto exit;
+ }
+ pcmd_node = pmadapter->curr_cmd;
+ if (pcmd_node->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_TIMEOUT;
+ }
+
+ if (pcmd_node) {
+ pmadapter->dbg.timeout_cmd_id =
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index];
+ pmadapter->dbg.timeout_cmd_act =
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index];
+ PRINTM_GET_SYS_TIME(MERROR, &sec, &usec);
+ PRINTM(MERROR, "Timeout cmd id (%lu.%06lu) = 0x%x, act = 0x%x \n", sec,
+ usec, pmadapter->dbg.timeout_cmd_id,
+ pmadapter->dbg.timeout_cmd_act);
+ if (pcmd_node->cmdbuf) {
+ t_u8 *pcmd_buf;
+ pcmd_buf =
+ pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset +
+ INTF_HEADER_LEN;
+ for (i = 0; i < 16; i++) {
+ PRINTM(MERROR, "%02x ", *pcmd_buf++);
+ }
+ PRINTM(MERROR, "\n");
+ }
+
+ pmpriv = pcmd_node->priv;
+ if (pmpriv) {
+ PRINTM(MERROR, "BSS type = %d BSS role= %d\n", pmpriv->bss_type,
+ pmpriv->bss_role);
+ }
+
+ PRINTM(MERROR, "num_cmd_timeout = %d\n",
+ pmadapter->dbg.num_cmd_timeout);
+ PRINTM(MERROR, "last_cmd_index = %d\n", pmadapter->dbg.last_cmd_index);
+ PRINTM(MERROR, "last_cmd_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_act = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_act[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n",
+ pmadapter->dbg.last_cmd_resp_index);
+ PRINTM(MERROR, "last_cmd_resp_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_resp_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_event_index = %d\n",
+ pmadapter->dbg.last_event_index);
+ PRINTM(MERROR, "last_event = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_event[i]);
+ }
+ PRINTM(MERROR, "\n");
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ pmadapter->dbg.num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ pmadapter->dbg.num_cmd_host_to_card_failure);
+ PRINTM(MERROR, "num_data_c2h_failure = %d\n",
+ pmadapter->dbg.num_rx_card_to_host_failure);
+ PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
+ pmadapter->dbg.num_cmdevt_card_to_host_failure);
+ PRINTM(MERROR, "num_int_read_failure = %d\n",
+ pmadapter->dbg.num_int_read_failure);
+ PRINTM(MERROR, "last_int_status = %d\n",
+ pmadapter->dbg.last_int_status);
+
+ PRINTM(MERROR, "num_event_deauth = %d\n",
+ pmadapter->dbg.num_event_deauth);
+ PRINTM(MERROR, "num_event_disassoc = %d\n",
+ pmadapter->dbg.num_event_disassoc);
+ PRINTM(MERROR, "num_event_link_lost = %d\n",
+ pmadapter->dbg.num_event_link_lost);
+ PRINTM(MERROR, "num_cmd_deauth = %d\n", pmadapter->dbg.num_cmd_deauth);
+ PRINTM(MERROR, "num_cmd_assoc_success = %d\n",
+ pmadapter->dbg.num_cmd_assoc_success);
+ PRINTM(MERROR, "num_cmd_assoc_failure = %d\n",
+ pmadapter->dbg.num_cmd_assoc_failure);
+ PRINTM(MERROR, "cmd_resp_received=%d\n", pmadapter->cmd_resp_received);
+ PRINTM(MERROR, "event_received=%d\n", pmadapter->event_received);
+
+ PRINTM(MERROR, "max_tx_buf_size=%d\n", pmadapter->max_tx_buf_size);
+ PRINTM(MERROR, "tx_buf_size=%d\n", pmadapter->tx_buf_size);
+ PRINTM(MERROR, "curr_tx_buf_size=%d\n", pmadapter->curr_tx_buf_size);
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", pmadapter->data_sent,
+ pmadapter->cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", pmadapter->ps_mode,
+ pmadapter->ps_state);
+ PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d\n",
+ pmadapter->pm_wakeup_card_req, pmadapter->pm_wakeup_fw_try);
+ PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
+ pmadapter->is_hs_configured, pmadapter->hs_activated);
+ PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n",
+ pmadapter->pps_uapsd_mode, pmadapter->sleep_period.period);
+ PRINTM(MERROR, "tx_lock_flag = %d\n", pmadapter->tx_lock_flag);
+ PRINTM(MERROR, "scan_processing = %d\n", pmadapter->scan_processing);
+
+ PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ pmadapter->mp_rd_bitmap, pmadapter->curr_rd_port);
+ PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ pmadapter->mp_wr_bitmap, pmadapter->curr_wr_port);
+ }
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing)
+ wlan_init_fw_complete(pmadapter);
+ else
+ /* Signal MOAL to perform extra handling for debugging */
+ if (pmpriv) {
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ } else {
+ wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ }
+
+ exit:
+ LEAVE();
+ return;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Internal function used to flush the scan pending queue
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_flush_scan_queue(IN pmlan_adapter pmadapter)
+{
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief Cancel all pending cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return N/A
+ */
+t_void
+wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+
+ ENTER();
+ /* Cancel current cmd */
+ wlan_request_cmd_lock(pmadapter);
+ if ((pmadapter->curr_cmd) && (pmadapter->curr_cmd->pioctl_buf)) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ /* Cancel all pending command */
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ pcmd_node->pioctl_buf = MNULL;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+#ifdef STA_SUPPORT
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+#endif
+ LEAVE();
+}
+
+/**
+ * @brief Cancel pending ioctl cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return N/A
+ */
+t_void
+wlan_cancel_pending_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "MOAL Cancel IOCTL: 0x%x sub_id=0x%x action=%d\n",
+ pioctl_req->req_id, *((t_u32 *) pioctl_req->pbuf),
+ (int) pioctl_req->action);
+
+ wlan_request_cmd_lock(pmadapter);
+ if ((pmadapter->curr_cmd) &&
+ (pmadapter->curr_cmd->pioctl_buf == pioctl_req)) {
+ pcmd_node = pmadapter->curr_cmd;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->cmd_flag |= CMD_F_CANCELED;
+ }
+
+ while ((pcmd_node =
+ wlan_get_pending_ioctl_cmd(pmadapter, pioctl_req)) != MNULL) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ wlan_request_cmd_lock(pmadapter);
+ }
+ wlan_release_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ if (pioctl_req->req_id == MLAN_IOCTL_SCAN) {
+ /* IOCTL will be completed, avoid calling IOCTL complete again from
+ EVENT */
+ if (pmadapter->pext_scan_ioctl_req == pioctl_req)
+ pmadapter->pext_scan_ioctl_req = MNULL;
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ }
+#endif
+ pioctl_req->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
+ MLAN_STATUS_FAILURE);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Handle the version_ext resp
+ *
+ * @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_ver_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_VERSION_EXT *ver_ext = &resp->params.verext;
+ mlan_ds_get_info *info;
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ info->param.ver_ext.version_str_sel = ver_ext->version_str_sel;
+ memcpy(pmpriv->adapter, info->param.ver_ext.version_str,
+ ver_ext->version_str, sizeof(char) * 128);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the rx mgmt forward registration resp
+ *
+ * @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_rx_mgmt_ind(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ ENTER();
+
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc->param.mgmt_subtype_mask =
+ wlan_le32_to_cpu(resp->params.rx_mgmt_ind.mgmt_subtype_mask);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks conditions and prepares to
+ * send sleep confirm command to firmware if OK.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_check_ps_cond(mlan_adapter * pmadapter)
+{
+ ENTER();
+
+ if (!pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !IS_CARD_RX_RCVD(pmadapter)) {
+ wlan_dnld_sleep_confirm_cmd(pmadapter);
+ } else {
+ PRINTM(MCMND, "Delay Sleep Confirm (%s%s%s)\n",
+ (pmadapter->cmd_sent) ? "D" : "",
+ (pmadapter->curr_cmd) ? "C" : "",
+ (IS_CARD_RX_RCVD(pmadapter)) ? "R" : "");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_ACTIVATED event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param activated MTRUE if activated, MFALSE if de-activated
+ *
+ * @return N/A
+ */
+t_void
+wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated)
+{
+ ENTER();
+
+ if (activated) {
+ if (priv->adapter->is_hs_configured) {
+ priv->adapter->hs_activated = MTRUE;
+ PRINTM(MEVENT, "hs_activated\n");
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_ACTIVATED, MNULL);
+ } else
+ PRINTM(MWARN, "hs_activated: HS not configured !!!\n");
+ } else {
+ PRINTM(MEVENT, "hs_deactived\n");
+ priv->adapter->hs_activated = MFALSE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_DEACTIVATED, MNULL);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_WAKEUP event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_host_sleep_wakeup_event(pmlan_private priv)
+{
+ ENTER();
+
+ if (priv->adapter->is_hs_configured) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_HS_WAKEUP, MNULL);
+ } else {
+ PRINTM(MWARN, "hs_wakeup: Host Sleep not configured !!!\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of hs_cfg
+ *
+ * @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_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &resp->params.opt_hs_cfg;
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(phs_cfg->action) == HS_ACTIVATE) {
+ /* clean up curr_cmd to allow suspend */
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_host_sleep_activated_event(pmpriv, MTRUE);
+ goto done;
+ } else {
+ phs_cfg->params.hs_config.conditions =
+ wlan_le32_to_cpu(phs_cfg->params.hs_config.conditions);
+ PRINTM(MCMND,
+ "CMD_RESP: HS_CFG cmd reply result=%#x,"
+ " conditions=0x%x gpio=0x%x gap=0x%x\n", resp->result,
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+ if (phs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) {
+ pmadapter->is_hs_configured = MTRUE;
+ } else {
+ pmadapter->is_hs_configured = MFALSE;
+ if (pmadapter->hs_activated)
+ wlan_host_sleep_activated_event(pmpriv, MFALSE);
+ }
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Perform hs related activities on receiving the power up interrupt
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @return N/A
+ */
+t_void
+wlan_process_hs_config(pmlan_adapter pmadapter)
+{
+ ENTER();
+ PRINTM(MINFO, "Recevie interrupt/data in HS mode\n");
+ if (pmadapter->hs_cfg.gap == HOST_SLEEP_CFG_GAP_FF)
+ wlan_pm_wakeup_card(pmadapter);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Check sleep confirm command response and set the state to ASLEEP
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @param pbuf A pointer to the command response buffer
+ * @param upld_len Command response buffer length
+ * @return N/A
+ */
+void
+wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
+ t_u32 upld_len)
+{
+ HostCmd_DS_COMMAND *cmd;
+
+ ENTER();
+
+ if (!upld_len) {
+ PRINTM(MERROR, "Command size is 0\n");
+ LEAVE();
+ return;
+ }
+ cmd = (HostCmd_DS_COMMAND *) pbuf;
+ cmd->result = wlan_le16_to_cpu(cmd->result);
+ cmd->command = wlan_le16_to_cpu(cmd->command);
+ cmd->seq_num = wlan_le16_to_cpu(cmd->seq_num);
+
+ /* Update sequence number */
+ cmd->seq_num = HostCmd_GET_SEQ_NO(cmd->seq_num);
+ /* Clear RET_BIT from HostCmd */
+ cmd->command &= HostCmd_CMD_ID_MASK;
+
+ if (cmd->command != HostCmd_CMD_802_11_PS_MODE_ENH) {
+ PRINTM(MERROR,
+ "Received unexpected response for command %x, result = %x\n",
+ cmd->command, cmd->result);
+ LEAVE();
+ return;
+ }
+ PRINTM(MEVENT, "#\n");
+ if (cmd->result != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Sleep confirm command failed\n");
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ LEAVE();
+ return;
+ }
+ pmadapter->pm_wakeup_card_req = MTRUE;
+
+ if (pmadapter->is_hs_configured) {
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY), MTRUE);
+ }
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ LEAVE();
+}
+
+/**
+ * @brief This function prepares command of power mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param ps_bitmap PS bitmap
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_enh_power_mode(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u16 ps_bitmap, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_PS_MODE_ENH *psmode_enh = &cmd->params.psmode_enh;
+ t_u8 *tlv = MNULL;
+ t_u16 cmd_size = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "PS Command: action = 0x%x, bitmap = 0x%x\n", cmd_action,
+ ps_bitmap);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ if (cmd_action == DIS_AUTO_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(DIS_AUTO_PS);
+ psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
+ } else if (cmd_action == GET_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(GET_PS);
+ psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
+ } else if (cmd_action == EN_AUTO_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(EN_AUTO_PS);
+ psmode_enh->params.auto_ps.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE;
+ tlv = (t_u8 *) cmd + cmd_size;
+ if (ps_bitmap & BITMAP_STA_PS) {
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypes_ps_param_t *ps_tlv = (MrvlIEtypes_ps_param_t *) tlv;
+ ps_param *ps_mode = &ps_tlv->param;
+ ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PS_PARAM);
+ ps_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_ps_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd_size += sizeof(MrvlIEtypes_ps_param_t);
+ tlv += sizeof(MrvlIEtypes_ps_param_t);
+ ps_mode->null_pkt_interval =
+ wlan_cpu_to_le16(pmadapter->null_pkt_interval);
+ ps_mode->multiple_dtims =
+ wlan_cpu_to_le16(pmadapter->multiple_dtim);
+ ps_mode->bcn_miss_timeout =
+ wlan_cpu_to_le16(pmadapter->bcn_miss_time_out);
+ ps_mode->local_listen_interval =
+ wlan_cpu_to_le16(pmadapter->local_listen_interval);
+ ps_mode->adhoc_wake_period =
+ wlan_cpu_to_le16(pmadapter->adhoc_awake_period);
+ ps_mode->delay_to_ps = wlan_cpu_to_le16(pmadapter->delay_to_ps);
+ ps_mode->mode = wlan_cpu_to_le16(pmadapter->enhanced_ps_mode);
+ }
+ if (ps_bitmap & BITMAP_AUTO_DS) {
+ MrvlIEtypes_auto_ds_param_t *auto_ps_tlv =
+ (MrvlIEtypes_auto_ds_param_t *) tlv;
+ auto_ds_param *auto_ds = &auto_ps_tlv->param;
+ t_u16 idletime = 0;
+ auto_ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
+ auto_ps_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_auto_ds_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd_size += sizeof(MrvlIEtypes_auto_ds_param_t);
+ tlv += sizeof(MrvlIEtypes_auto_ds_param_t);
+ if (pdata_buf)
+ idletime = ((mlan_ds_auto_ds *) pdata_buf)->idletime;
+ auto_ds->deep_sleep_timeout = wlan_cpu_to_le16(idletime);
+ }
+#if defined(UAP_SUPPORT)
+ if (pdata_buf &&
+ (ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS))) {
+ mlan_ds_ps_mgmt *ps_mgmt = (mlan_ds_ps_mgmt *) pdata_buf;
+ MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL;
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL;
+ if (ps_mgmt->flags & PS_FLAG_SLEEP_PARAM) {
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
+ sleep_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AP_SLEEP_PARAM);
+ sleep_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_sleep_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ sleep_tlv->ctrl_bitmap =
+ wlan_cpu_to_le32(ps_mgmt->sleep_param.ctrl_bitmap);
+ sleep_tlv->min_sleep =
+ wlan_cpu_to_le32(ps_mgmt->sleep_param.min_sleep);
+ sleep_tlv->max_sleep =
+ wlan_cpu_to_le32(ps_mgmt->sleep_param.max_sleep);
+ cmd_size += sizeof(MrvlIEtypes_sleep_param_t);
+ tlv += sizeof(MrvlIEtypes_sleep_param_t);
+ }
+ if (ps_mgmt->flags & PS_FLAG_INACT_SLEEP_PARAM) {
+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
+ inact_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AP_INACT_SLEEP_PARAM);
+ inact_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_inact_sleep_param_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ inact_tlv->inactivity_to =
+ wlan_cpu_to_le32(ps_mgmt->inact_param.inactivity_to);
+ inact_tlv->min_awake =
+ wlan_cpu_to_le32(ps_mgmt->inact_param.min_awake);
+ inact_tlv->max_awake =
+ wlan_cpu_to_le32(ps_mgmt->inact_param.max_awake);
+ cmd_size += sizeof(MrvlIEtypes_inact_sleep_param_t);
+ tlv += sizeof(MrvlIEtypes_inact_sleep_param_t);
+ }
+ }
+#endif
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ps_mode_enh
+ *
+ * @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_enh_power_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypesHeader_t *mrvl_tlv = MNULL;
+ MrvlIEtypes_auto_ds_param_t *auto_ds_tlv = MNULL;
+ HostCmd_DS_802_11_PS_MODE_ENH *ps_mode = &resp->params.psmode_enh;
+
+ ENTER();
+
+ ps_mode->action = wlan_le16_to_cpu(ps_mode->action);
+ PRINTM(MINFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ resp->result, ps_mode->action);
+ if (ps_mode->action == EN_AUTO_PS) {
+ ps_mode->params.auto_ps.ps_bitmap =
+ wlan_le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap);
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_AUTO_DS) {
+ PRINTM(MCMND, "Enabled auto deep sleep\n");
+ pmpriv->adapter->is_deep_sleep = MTRUE;
+ mrvl_tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) ps_mode + AUTO_PS_FIX_SIZE);
+ while (wlan_le16_to_cpu(mrvl_tlv->type) != TLV_TYPE_AUTO_DS_PARAM) {
+ mrvl_tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) mrvl_tlv +
+ wlan_le16_to_cpu(mrvl_tlv->len)
+ + sizeof(MrvlIEtypesHeader_t));
+ }
+ auto_ds_tlv = (MrvlIEtypes_auto_ds_param_t *) mrvl_tlv;
+ pmpriv->adapter->idle_time =
+ wlan_le16_to_cpu(auto_ds_tlv->param.deep_sleep_timeout);
+ }
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) {
+ PRINTM(MCMND, "Enabled STA power save\n");
+ if (pmadapter->sleep_period.period) {
+ PRINTM(MCMND, "Setting uapsd/pps mode to TRUE\n");
+ }
+ }
+#if defined(UAP_SUPPORT)
+ if (ps_mode->params.auto_ps.
+ ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) {
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ PRINTM(MCMND, "Enabled uAP power save\n");
+ }
+#endif
+ } else if (ps_mode->action == DIS_AUTO_PS) {
+ ps_mode->params.ps_bitmap = wlan_cpu_to_le16(ps_mode->params.ps_bitmap);
+ if (ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) {
+ pmpriv->adapter->is_deep_sleep = MFALSE;
+ PRINTM(MCMND, "Disabled auto deep sleep\n");
+ }
+ if (ps_mode->params.ps_bitmap & BITMAP_STA_PS) {
+ PRINTM(MCMND, "Disabled STA power save\n");
+ if (pmadapter->sleep_period.period) {
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->pps_uapsd_mode = MFALSE;
+ }
+ }
+#if defined(UAP_SUPPORT)
+ if (ps_mode->params.
+ ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) {
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ PRINTM(MCMND, "Disabled uAP power save\n");
+ }
+#endif
+ } else if (ps_mode->action == GET_PS) {
+ ps_mode->params.ps_bitmap = wlan_le16_to_cpu(ps_mode->params.ps_bitmap);
+ if (ps_mode->params.auto_ps.
+ ps_bitmap & (BITMAP_STA_PS | BITMAP_UAP_INACT_PS |
+ BITMAP_UAP_DTIM_PS))
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ PRINTM(MCMND, "ps_bitmap=0x%x\n", ps_mode->params.ps_bitmap);
+ if (pioctl_buf) {
+ mlan_ds_pm_cfg *pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ if (pm_cfg->sub_command == MLAN_OID_PM_CFG_IEEE_PS) {
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS)
+ pm_cfg->param.ps_mode = 1;
+ else
+ pm_cfg->param.ps_mode = 0;
+ }
+#if defined(UAP_SUPPORT)
+ if (pm_cfg->sub_command == MLAN_OID_PM_CFG_PS_MODE) {
+ MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL;
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ t_u16 tlv_buf_left = 0;
+ pm_cfg->param.ps_mgmt.flags = PS_FLAG_PS_MODE;
+ if (ps_mode->params.ps_bitmap & BITMAP_UAP_INACT_PS)
+ pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_INACTIVITY;
+ else if (ps_mode->params.ps_bitmap & BITMAP_UAP_DTIM_PS)
+ pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_PERIODIC_DTIM;
+ else
+ pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_DISABLE;
+ tlv_buf_left = resp->size - (S_DS_GEN + AUTO_PS_FIX_SIZE);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) ps_mode +
+ AUTO_PS_FIX_SIZE);
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ switch (tlv_type) {
+ case TLV_TYPE_AP_SLEEP_PARAM:
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
+ pm_cfg->param.ps_mgmt.flags |= PS_FLAG_SLEEP_PARAM;
+ pm_cfg->param.ps_mgmt.sleep_param.ctrl_bitmap =
+ wlan_le32_to_cpu(sleep_tlv->ctrl_bitmap);
+ pm_cfg->param.ps_mgmt.sleep_param.min_sleep =
+ wlan_le32_to_cpu(sleep_tlv->min_sleep);
+ pm_cfg->param.ps_mgmt.sleep_param.max_sleep =
+ wlan_le32_to_cpu(sleep_tlv->max_sleep);
+ break;
+ case TLV_TYPE_AP_INACT_SLEEP_PARAM:
+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
+ pm_cfg->param.ps_mgmt.flags |=
+ PS_FLAG_INACT_SLEEP_PARAM;
+ pm_cfg->param.ps_mgmt.inact_param.inactivity_to =
+ wlan_le32_to_cpu(inact_tlv->inactivity_to);
+ pm_cfg->param.ps_mgmt.inact_param.min_awake =
+ wlan_le32_to_cpu(inact_tlv->min_awake);
+ pm_cfg->param.ps_mgmt.inact_param.max_awake =
+ wlan_le32_to_cpu(inact_tlv->max_awake);
+ break;
+ }
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+#endif
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx rate query
+ *
+ * @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_802_11_tx_rate_query(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *rate = MNULL;
+ ENTER();
+
+ pmpriv->tx_rate = resp->params.tx_rate.tx_rate;
+ pmpriv->tx_htinfo = resp->params.tx_rate.ht_info;
+ if (!pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate = wlan_index_to_data_rate(pmadapter,
+ pmpriv->tx_rate,
+ pmpriv->tx_htinfo);
+ }
+
+ if (pioctl_buf) {
+ rate = (mlan_ds_rate *) pioctl_buf->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG) {
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) {
+ if (pmpriv->tx_htinfo & MBIT(0))
+ rate->param.rate_cfg.rate =
+ pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
+ else
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, there is a hole in
+ rate table between HR/DSSS and OFDM rates, so minus 1
+ for OFDM rate index */
+ rate->param.rate_cfg.rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate -
+ 1 : pmpriv->tx_rate;
+ } else {
+ rate->param.rate_cfg.rate =
+ wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_htinfo);
+ }
+ } else if (rate->sub_command == MLAN_OID_GET_DATA_RATE) {
+ if (pmpriv->tx_htinfo & MBIT(0)) {
+ rate->param.data_rate.tx_data_rate =
+ pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
+ if (pmpriv->tx_htinfo & MBIT(1))
+ rate->param.data_rate.tx_ht_bw = MLAN_HT_BW40;
+ else
+ rate->param.data_rate.tx_ht_bw = MLAN_HT_BW20;
+ if (pmpriv->tx_htinfo & MBIT(2))
+ rate->param.data_rate.tx_ht_gi = MLAN_HT_SGI;
+ else
+ rate->param.data_rate.tx_ht_gi = MLAN_HT_LGI;
+ } else
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, there is a hole in
+ rate table between HR/DSSS and OFDM rates, so minus 1 for
+ OFDM rate index */
+ rate->param.data_rate.tx_data_rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate -
+ 1 : pmpriv->tx_rate;
+ if (pmpriv->rxpd_htinfo & MBIT(0)) {
+ rate->param.data_rate.rx_data_rate =
+ pmpriv->rxpd_rate + MLAN_RATE_INDEX_MCS0;
+ if (pmpriv->rxpd_htinfo & MBIT(1))
+ rate->param.data_rate.rx_ht_bw = MLAN_HT_BW40;
+ else
+ rate->param.data_rate.rx_ht_bw = MLAN_HT_BW20;
+ if (pmpriv->tx_htinfo & MBIT(2))
+ rate->param.data_rate.rx_ht_gi = MLAN_HT_SGI;
+ else
+ rate->param.data_rate.rx_ht_gi = MLAN_HT_LGI;
+ } else
+ /* For rate index in RxPD, there is a hole in rate table
+ between HR/DSSS and OFDM rates, so minus 1 for OFDM rate
+ index */
+ rate->param.data_rate.rx_data_rate =
+ (pmpriv->rxpd_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->rxpd_rate -
+ 1 : pmpriv->rxpd_rate;
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_rate_cfg.
+ *
+ * @param pmpriv 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_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_TX_RATE_CFG *rate_cfg = &cmd->params.tx_rate_cfg;
+ MrvlRateScope_t *rate_scope;
+ MrvlRateDropPattern_t *rate_drop;
+ t_u16 *pbitmap_rates = (t_u16 *) pdata_buf;
+
+ t_u32 i;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
+
+ rate_cfg->action = wlan_cpu_to_le16(cmd_action);
+ rate_cfg->cfg_index = 0;
+
+ rate_scope = (MrvlRateScope_t *) ((t_u8 *) rate_cfg +
+ sizeof(HostCmd_DS_TX_RATE_CFG));
+ rate_scope->type = wlan_cpu_to_le16(TLV_TYPE_RATE_SCOPE);
+ rate_scope->length = wlan_cpu_to_le16(sizeof(MrvlRateScope_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (pbitmap_rates != MNULL) {
+ rate_scope->hr_dsss_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[1]);
+ for (i = 0; i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pbitmap_rates[2 + i]);
+ } else {
+ rate_scope->hr_dsss_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[1]);
+ for (i = 0; i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[2 + i]);
+ }
+
+ rate_drop = (MrvlRateDropPattern_t *) ((t_u8 *) rate_scope +
+ sizeof(MrvlRateScope_t));
+ rate_drop->type = wlan_cpu_to_le16(TLV_TYPE_RATE_DROP_PATTERN);
+ rate_drop->length = wlan_cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
+ rate_drop->rate_drop_mode = 0;
+
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) +
+ sizeof(MrvlRateScope_t) +
+ sizeof(MrvlRateDropPattern_t));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_rate_cfg
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *ds_rate = MNULL;
+ HostCmd_DS_TX_RATE_CFG *prate_cfg = MNULL;
+ MrvlRateScope_t *prate_scope;
+ MrvlIEtypesHeader_t *head = MNULL;
+ t_u16 tlv, tlv_buf_len;
+ t_u8 *tlv_buf;
+ t_u32 i;
+ t_s32 index;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (resp == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ prate_cfg = &resp->params.tx_rate_cfg;
+
+ tlv_buf = (t_u8 *) ((t_u8 *) prate_cfg) + sizeof(HostCmd_DS_TX_RATE_CFG);
+ tlv_buf_len = *(t_u16 *) (tlv_buf + sizeof(t_u16));
+ tlv_buf_len = wlan_le16_to_cpu(tlv_buf_len);
+
+ while (tlv_buf && tlv_buf_len > 0) {
+ tlv = (*tlv_buf);
+ tlv = tlv | (*(tlv_buf + 1) << 8);
+
+ switch (tlv) {
+ case TLV_TYPE_RATE_SCOPE:
+ prate_scope = (MrvlRateScope_t *) tlv_buf;
+ pmpriv->bitmap_rates[0] =
+ wlan_le16_to_cpu(prate_scope->hr_dsss_rate_bitmap);
+ pmpriv->bitmap_rates[1] =
+ wlan_le16_to_cpu(prate_scope->ofdm_rate_bitmap);
+ for (i = 0;
+ i < sizeof(prate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ pmpriv->bitmap_rates[2 + i] =
+ wlan_le16_to_cpu(prate_scope->ht_mcs_rate_bitmap[i]);
+ break;
+ /* Add RATE_DROP tlv here */
+ }
+
+ head = (MrvlIEtypesHeader_t *) tlv_buf;
+ head->len = wlan_le16_to_cpu(head->len);
+ tlv_buf += head->len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -= head->len;
+ }
+
+ pmpriv->is_data_rate_auto = wlan_is_rate_auto(pmpriv);
+
+ if (pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate = 0;
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+
+ }
+
+ if (pioctl_buf) {
+ ds_rate = (mlan_ds_rate *) pioctl_buf->pbuf;
+ if (ds_rate == MNULL) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmpriv->is_data_rate_auto) {
+ ds_rate->param.rate_cfg.is_rate_auto = MTRUE;
+ } else {
+ ds_rate->param.rate_cfg.is_rate_auto = MFALSE;
+ /* check the LG rate */
+ index = wlan_get_rate_index(pmadapter, &pmpriv->bitmap_rates[0], 4);
+ if (index != -1) {
+ if ((index >= MLAN_RATE_BITMAP_OFDM0) &&
+ (index <= MLAN_RATE_BITMAP_OFDM7))
+ index -= (MLAN_RATE_BITMAP_OFDM0 - MLAN_RATE_INDEX_OFDM0);
+ ds_rate->param.rate_cfg.rate = index;
+ }
+ /* check the HT rate */
+ index = wlan_get_rate_index(pmadapter,
+ &pmpriv->bitmap_rates[2], 16);
+ if (index != -1) {
+ ds_rate->param.rate_cfg.rate = index + MLAN_RATE_INDEX_MCS0;
+ }
+ PRINTM(MINFO, "Rate index is %d\n", ds_rate->param.rate_cfg.rate);
+ }
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ ds_rate->param.rate_cfg.bitmap_rates[i] = pmpriv->bitmap_rates[i];
+ }
+
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues adapter specific commands
+ * to initialize firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_adapter_init_cmd(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = MNULL;
+#ifdef STA_SUPPORT
+ pmlan_private pmpriv_sta = MNULL;
+#endif
+
+ ENTER();
+
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+#ifdef STA_SUPPORT
+ pmpriv_sta = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA);
+#endif
+
+ /*
+ * This should be issued in the very first to config
+ * SDIO_GPIO interrupt mode.
+ */
+ if (wlan_set_sdio_gpio_int(pmpriv) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_INIT,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /** Cal data dnld cmd prepare */
+ if ((pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) {
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_CFG_DATA, HostCmd_ACT_GEN_SET,
+ 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pcal_data = MNULL;
+ pmadapter->cal_data_len = 0;
+ }
+
+ /*
+ * Get HW spec
+ */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_HW_SPEC,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Reconfigure tx buf size */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmadapter->max_tx_buf_size);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if defined(STA_SUPPORT)
+ if (pmpriv_sta && (pmpriv_sta->state_11d.user_enable_11d == ENABLE_11D)) {
+ /* Send command to FW to enable 11d */
+ ret = wlan_prepare_cmd(pmpriv_sta,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11D_i,
+ MNULL, &pmpriv_sta->state_11d.user_enable_11d);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+
+#if defined(STA_SUPPORT)
+ if (pmpriv_sta && (pmadapter->ps_mode == Wlan802_11PowerModePSP)) {
+ ret = wlan_prepare_cmd(pmpriv_sta, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_STA_PS, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+
+ if (pmadapter->init_auto_ds) {
+ mlan_ds_auto_ds auto_ds;
+ /* Enable auto deep sleep */
+ auto_ds.idletime = pmadapter->idle_time;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_AUTO_DS, MNULL, &auto_ds);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of get_hw_spec.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_get_hw_spec(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND * pcmd)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &pcmd->params.hw_spec;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
+ memcpy(pmpriv->adapter, hw_spec->permanent_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of set_cfg_data.
+ *
+ * @param pmpriv A pointer to mlan_private strcture
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action: GET or SET
+ * @param pdata_buf A pointer to cal_data buf
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11_CFG_DATA *pcfg_data = &(pcmd->params.cfg_data);
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u32 len;
+ t_u32 cal_data_offset;
+ t_u8 *temp_pcmd = (t_u8 *) pcmd;
+
+ ENTER();
+
+ cal_data_offset = S_DS_GEN + sizeof(HostCmd_DS_802_11_CFG_DATA);
+ if ((pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) {
+ len = wlan_parse_cal_cfg((t_u8 *) pmadapter->pcal_data,
+ pmadapter->cal_data_len,
+ (t_u8 *) (temp_pcmd + cal_data_offset));
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pcfg_data->action = cmd_action;
+ pcfg_data->type = 2; /* cal data type */
+ pcfg_data->data_len = len;
+
+ pcmd->command = HostCmd_CMD_CFG_DATA;
+ pcmd->size = pcfg_data->data_len + cal_data_offset;
+
+ pcmd->command = wlan_cpu_to_le16(pcmd->command);
+ pcmd->size = wlan_cpu_to_le16(pcmd->size);
+
+ pcfg_data->action = wlan_cpu_to_le16(pcfg_data->action);
+ pcfg_data->type = wlan_cpu_to_le16(pcfg_data->type);
+ pcfg_data->data_len = wlan_cpu_to_le16(pcfg_data->data_len);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of set_cfg_data
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to A pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (resp->result != HostCmd_RESULT_OK) {
+ PRINTM(MERROR, "Cal data cmd resp failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of get_hw_spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &resp->params.hw_spec;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 i;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info);
+#ifdef STA_SUPPORT
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ pmadapter->fw_bands = (t_u8) GET_FW_DEFAULT_BANDS(pmadapter);
+ } else {
+ pmadapter->fw_bands = BAND_B;
+ }
+
+ pmadapter->config_bands = pmadapter->fw_bands;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands = pmadapter->fw_bands;
+ }
+
+ if (pmadapter->fw_bands & BAND_A) {
+ if (pmadapter->fw_bands & BAND_GN) {
+ pmadapter->config_bands |= BAND_AN;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |= BAND_AN;
+ }
+
+ pmadapter->fw_bands |= BAND_AN;
+ }
+ if ((pmadapter->fw_bands & BAND_AN)
+ ) {
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else
+ pmadapter->adhoc_start_band = BAND_A;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
+ } else if ((pmadapter->fw_bands & BAND_GN)
+ ) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else if (pmadapter->fw_bands & BAND_G) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ } else if (pmadapter->fw_bands & BAND_B) {
+ pmadapter->adhoc_start_band = BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ }
+#endif /* STA_SUPPORT */
+
+ pmadapter->fw_release_number = hw_spec->fw_release_number;
+ pmadapter->number_of_antenna = wlan_le16_to_cpu(hw_spec->number_of_antenna);
+
+ PRINTM(MINFO, "GET_HW_SPEC: fw_release_number- 0x%X\n",
+ wlan_le32_to_cpu(pmadapter->fw_release_number));
+ PRINTM(MINFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+ hw_spec->permanent_addr[0], hw_spec->permanent_addr[1],
+ hw_spec->permanent_addr[2], hw_spec->permanent_addr[3],
+ hw_spec->permanent_addr[4], hw_spec->permanent_addr[5]);
+ PRINTM(MINFO, "GET_HW_SPEC: hw_if_version=0x%X version=0x%X\n",
+ wlan_le16_to_cpu(hw_spec->hw_if_version),
+ wlan_le16_to_cpu(hw_spec->version));
+
+ if (pmpriv->curr_addr[0] == 0xff)
+ memmove(pmadapter, pmpriv->curr_addr, hw_spec->permanent_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ pmadapter->hw_dot_11n_dev_cap = wlan_le32_to_cpu(hw_spec->dot_11n_dev_cap);
+ pmadapter->usr_dot_11n_dev_cap_bg = pmadapter->hw_dot_11n_dev_cap &
+ DEFAULT_11N_CAP_MASK_BG;
+ pmadapter->usr_dot_11n_dev_cap_a = pmadapter->hw_dot_11n_dev_cap &
+ DEFAULT_11N_CAP_MASK_A;
+ pmadapter->usr_dev_mcs_support = pmadapter->hw_dev_mcs_support =
+ hw_spec->dev_mcs_support;
+ wlan_show_dot11ndevcap(pmadapter, pmadapter->hw_dot_11n_dev_cap);
+ wlan_show_devmcssupport(pmadapter, pmadapter->hw_dev_mcs_support);
+ pmadapter->mp_end_port = wlan_le16_to_cpu(hw_spec->mp_end_port);
+
+ for (i = 1; i <= (unsigned) (MAX_PORT - pmadapter->mp_end_port); i++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
+ }
+
+ pmadapter->max_mgmt_ie_index = wlan_le16_to_cpu(hw_spec->mgmt_buf_count);
+ PRINTM(MINFO, "GET_HW_SPEC: mgmt IE count=%d\n",
+ pmadapter->max_mgmt_ie_index);
+ if (!pmadapter->max_mgmt_ie_index)
+ pmadapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+
+ pmadapter->region_code = wlan_le16_to_cpu(hw_spec->region_code);
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (pmadapter->region_code == region_code_index[i])
+ break;
+ }
+ /* If it's unidentified region code, use the default */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ pmadapter->region_code = MRVDRV_DEFAULT_REGION_CODE;
+ PRINTM(MWARN, "unidentified region code, use the default (0x%02x)\n",
+ MRVDRV_DEFAULT_REGION_CODE);
+ }
+ /* Synchronize CFP code with region code */
+ pmadapter->cfp_code_bg = pmadapter->region_code;
+ pmadapter->cfp_code_a = pmadapter->region_code;
+
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->fw_bands)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ if (wlan_11d_set_universaltable(pmpriv, pmadapter->fw_bands)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif /* STA_SUPPORT */
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of radio_control.
+ *
+ * @param pmpriv 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_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_control = &cmd->params.radio;
+ t_u32 radio_ctl;
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
+ pradio_control->action = wlan_cpu_to_le16(cmd_action);
+ memcpy(pmpriv->adapter, &radio_ctl, pdata_buf, sizeof(t_u32));
+ pradio_control->control = wlan_cpu_to_le16((t_u16) radio_ctl);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of radio_control
+ *
+ * @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_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_ctrl =
+ (HostCmd_DS_802_11_RADIO_CONTROL *) & resp->params.radio;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+ pmadapter->radio_on = wlan_le16_to_cpu(pradio_ctrl->control);
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio_cfg->param.radio_on_off = (t_u32) pmadapter->radio_on;
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief This function prepares command of remain_on_channel.
+ *
+ * @param pmpriv 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_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel = &cmd->params.remain_on_chan;
+ mlan_ds_remain_chan *cfg = (mlan_ds_remain_chan *) pdata_buf;
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_REMAIN_ON_CHANNEL))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_REMAIN_ON_CHANNEL);
+ remain_channel->action = cmd_action;
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if (cfg->remove) {
+ remain_channel->action = HostCmd_ACT_GEN_REMOVE;
+ } else {
+ remain_channel->bandcfg = cfg->bandcfg;
+ remain_channel->channel = cfg->channel;
+ remain_channel->remain_period =
+ wlan_cpu_to_le32(cfg->remain_period);
+ }
+ }
+ remain_channel->action = wlan_cpu_to_le16(remain_channel->action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of remain_on_channel
+ *
+ * @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_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel = &resp->params.remain_on_chan;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio_cfg->param.remain_chan.status = remain_channel->status;
+ radio_cfg->param.remain_chan.bandcfg = remain_channel->bandcfg;
+ radio_cfg->param.remain_chan.channel = remain_channel->channel;
+ radio_cfg->param.remain_chan.remain_period =
+ wlan_le32_to_cpu(remain_channel->remain_period);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of wifi direct mode.
+ *
+ * @param pmpriv 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_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &cmd->params.wifi_direct_mode;
+ t_u16 mode = *((t_u16 *) pdata_buf);
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_WIFI_DIRECT_MODE))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_WIFI_DIRECT_MODE_CONFIG);
+ wfd_mode->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ wfd_mode->mode = wlan_cpu_to_le16(mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of wifi direct mode
+ *
+ * @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_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &resp->params.wifi_direct_mode;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ bss->param.wfd_mode = wlan_le16_to_cpu(wfd_mode->mode);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_bss);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_decl.h b/drivers/net/wireless/sd8797/mlan/mlan_decl.h
new file mode 100644
index 000000000000..41cf2bf5f2f1
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_decl.h
@@ -0,0 +1,893 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ * 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/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "311"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef char t_s8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8;
+/** Signed short (2-bytes) */
+typedef short t_s16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16;
+/** Signed long (4-bytes) */
+typedef int t_s32;
+/** Unsigned long (4-bytes) */
+typedef unsigned int t_u32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64;
+/** Void pointer (4-bytes) */
+typedef void t_void;
+/** Size type */
+typedef t_u32 t_size;
+/** Boolean type */
+typedef t_u8 t_bool;
+
+#ifdef MLAN_64BIT
+/** Pointer type (64-bit) */
+typedef t_u64 t_ptr;
+/** Signed value (64-bit) */
+typedef t_s64 t_sval;
+#else
+/** Pointer type (32-bit) */
+typedef t_u32 t_ptr;
+/** Signed value (32-bit) */
+typedef t_s32 t_sval;
+#endif
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__ ((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifndef INLINE
+#ifdef __GNUC__
+/** inline directive */
+#define INLINE inline
+#else
+/** inline directive */
+#define INLINE __inline
+#endif
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1))
+
+/** Return the byte offset of a field in the given structure */
+#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr)&(((type *)0)->field))
+/** Return aligned offset */
+#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p)
+
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (16)
+
+/** NET IP alignment */
+#define MLAN_NET_IP_ALIGN 0
+
+/** DMA alignment */
+#define DMA_ALIGNMENT 64
+/** max size of TxPD */
+#define MAX_TXPD_SIZE 32
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT+MAX_TXPD_SIZE)
+
+/** rx data header length */
+#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN
+
+/** This is current limit on Maximum Tx AMPDU allowed */
+#define MLAN_MAX_TX_BASTREAM_SUPPORTED 2
+/** This is current limit on Maximum Rx AMPDU allowed */
+#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+
+#ifdef STA_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_STA_AMPDU_DEF_TXWINSIZE 16
+/** Default Win size attached during ADDBA response */
+#define MLAN_STA_AMPDU_DEF_RXWINSIZE 32
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 32
+/** Default Win size attached during ADDBA response */
+#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 16
+#endif /* UAP_SUPPORT */
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+/** Maximum Tx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff
+/** Maximum Rx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 12
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 19
+/** Rate index for MCS 9 */
+#define MLAN_RATE_INDEX_MCS9 21
+/** Rate index for MCS15 */
+#define MLAN_RATE_INDEX_MCS15 27
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 44
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 139
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+
+/** Size of rx data buffer */
+#define MLAN_RX_DATA_BUF_SIZE (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE (2 * 1024)
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE (4 * 1024)
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+
+/** Max retry number of IO write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+/** Buffer flag for transmit buf from moal */
+#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1)
+/** Buffer flag for malloc mlan_buffer */
+#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2)
+
+/** Buffer flag for bridge packet */
+#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+#define MIOCTL MBIT(7)
+
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MEVT_D MBIT(18)
+#define MFW_D MBIT(19)
+#define MIF_D MBIT(20)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** Memory allocation type: DMA */
+#define MLAN_MEM_DMA MBIT(0)
+
+/** Default memory allocation flag */
+#define MLAN_MEM_DEF 0
+
+/** mlan_status */
+typedef enum _mlan_status
+{
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code
+{
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware/device errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY,
+ MLAN_ERROR_FW_CMDRESP,
+ MLAN_ERROR_DATA_TX_FAIL,
+ MLAN_ERROR_DATA_RX_FAIL,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT,
+ MLAN_ERROR_PKT_INVALID,
+ MLAN_ERROR_CMD_INVALID,
+ MLAN_ERROR_CMD_TIMEOUT,
+ MLAN_ERROR_CMD_DNLD_FAIL,
+ MLAN_ERROR_CMD_CANCEL,
+ MLAN_ERROR_CMD_RESP_FAIL,
+ MLAN_ERROR_CMD_ASSOC_FAIL,
+ MLAN_ERROR_CMD_SCAN_FAIL,
+ MLAN_ERROR_IOCTL_INVALID,
+ MLAN_ERROR_IOCTL_FAIL,
+ MLAN_ERROR_EVENT_UNKNOWN,
+ MLAN_ERROR_INVALID_PARAMETER,
+ MLAN_ERROR_NO_MEM,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type
+{
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+ MLAN_BUF_TYPE_RAW_DATA,
+} mlan_buf_type;
+
+/** MLAN BSS type */
+typedef enum _mlan_bss_type
+{
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP = 1,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_BSS_TYPE_WIFIDIRECT = 2,
+#endif
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** MLAN BSS role */
+typedef enum _mlan_bss_role
+{
+ MLAN_BSS_ROLE_STA = 0,
+ MLAN_BSS_ROLE_UAP = 1,
+ MLAN_BSS_ROLE_ANY = 0xff,
+} mlan_bss_role;
+
+/** BSS role bit mask */
+#define BSS_ROLE_BIT_MASK MBIT(0)
+
+/** Get BSS role */
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type
+{
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id
+{
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
+ MLAN_EVENT_ID_FW_DISCONNECTED,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH,
+ MLAN_EVENT_ID_FW_MAX_FAIL,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH,
+ MLAN_EVENT_ID_FW_LINK_QUALITY,
+ MLAN_EVENT_ID_FW_PORT_RELEASE,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
+ MLAN_EVENT_ID_FW_HS_WAKEUP,
+ MLAN_EVENT_ID_FW_BG_SCAN,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR,
+ MLAN_EVENT_ID_FW_STOP_TX,
+ MLAN_EVENT_ID_FW_START_TX,
+ MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY,
+ MLAN_EVENT_ID_FW_BW_CHANGED,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED,
+#endif
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_UAP_FW_BSS_START,
+ MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE,
+ MLAN_EVENT_ID_UAP_FW_BSS_IDLE,
+ MLAN_EVENT_ID_UAP_FW_STA_CONNECT,
+ MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT,
+#endif
+
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED,
+ MLAN_EVENT_ID_DRV_MGMT_FRAME,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM,
+ MLAN_EVENT_ID_DRV_PASSTHRU,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT,
+ MLAN_EVENT_ID_DRV_MEAS_REPORT,
+ MLAN_EVENT_ID_DRV_REPORT_STRING,
+ MLAN_EVENT_ID_DRV_DBG_DUMP,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image
+{
+ /** Helper image buffer pointer */
+ t_u8 *phelper_buf;
+ /** Helper image length */
+ t_u32 helper_len;
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** Custom data structure */
+typedef struct _mlan_init_param
+{
+ /** Cal data buffer pointer */
+ t_u8 *pcal_data_buf;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Other custom data */
+} mlan_init_param, *pmlan_init_param;
+
+/** mlan_event data structure */
+typedef struct _mlan_event
+{
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[1];
+} mlan_event, *pmlan_event;
+
+/** mlan_event_scan_result data structure */
+typedef MLAN_PACK_START struct _mlan_event_scan_result
+{
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** More event available or not */
+ t_u8 more_event;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** Size of the response buffer */
+ t_u16 buf_size;
+ /** Number of BSS in scan response */
+ t_u8 num_of_set;
+} MLAN_PACK_END mlan_event_scan_result, *pmlan_event_scan_result;
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req
+{
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_ptr reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer
+{
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+} mlan_buffer, *pmlan_buffer;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr
+{
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+ /** BSS number */
+ t_u32 bss_num;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e
+{
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e
+{
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e
+{
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e
+{
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t,
+/** Type definition of mlan_ds_wmm_ts_status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie
+{
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+/** Max IE index to FW */
+#define MAX_MGMT_IE_INDEX_TO_FW 4
+/** Max IE index per BSS */
+#define MAX_MGMT_IE_INDEX 16
+
+/** custom IE info */
+typedef MLAN_PACK_START struct _custom_ie_info
+{
+ /** size of buffer */
+ t_u16 buf_size;
+ /** no of buffers of buf_size */
+ t_u16 buf_count;
+} MLAN_PACK_END custom_ie_info;
+
+/** TLV buffer : Max Mgmt IE */
+typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** No of tuples */
+ t_u16 count;
+ /** custom IE info tuples */
+ custom_ie_info info[MAX_MGMT_IE_INDEX];
+} MLAN_PACK_END tlvbuf_max_mgmt_ie;
+
+/** TLV buffer : custom IE */
+typedef MLAN_PACK_START struct _tlvbuf_custom_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** IE data */
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW];
+ /** Max mgmt IE TLV */
+ tlvbuf_max_mgmt_ie max_mgmt_ie;
+} MLAN_PACK_END mlan_ds_misc_custom_ie;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks
+{
+ /** moal_get_fw_data */
+ mlan_status(*moal_get_fw_data) (IN t_void * pmoal_handle,
+ IN t_u32 offset,
+ IN t_u32 len, OUT t_u8 * pbuf);
+ /** moal_init_fw_complete */
+ mlan_status(*moal_init_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status(*moal_shutdown_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status(*moal_send_packet_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+ /** moal_recv_complete */
+ mlan_status(*moal_recv_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN mlan_status status);
+ /** moal_recv_packet */
+ mlan_status(*moal_recv_packet) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status(*moal_recv_event) (IN t_void * pmoal_handle,
+ IN pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status(*moal_ioctl_complete) (IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+ /** moal_alloc_mlan_buffer */
+ mlan_status(*moal_alloc_mlan_buffer) (IN t_void * pmoal_handle,
+ IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status(*moal_free_mlan_buffer) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_write_reg */
+ mlan_status(*moal_write_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+ /** moal_read_reg */
+ mlan_status(*moal_read_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+ /** moal_write_data_sync */
+ mlan_status(*moal_write_data_sync) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status(*moal_read_data_sync) (IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_malloc */
+ mlan_status(*moal_malloc) (IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf);
+ /** moal_mfree */
+ mlan_status(*moal_mfree) (IN t_void * pmoal_handle, IN t_u8 * pbuf);
+ /** moal_memset */
+ t_void *(*moal_memset) (IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memmove */
+ t_void *(*moal_memmove) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memcmp */
+ t_s32(*moal_memcmp) (IN t_void * pmoal_handle,
+ IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+ /** moal_udelay */
+ t_void(*moal_udelay) (IN t_void * pmoal_handle, IN t_u32 udelay);
+ /** moal_get_system_time */
+ mlan_status(*moal_get_system_time) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec, OUT t_u32 * pusec);
+ /** moal_init_timer*/
+ mlan_status(*moal_init_timer) (IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+ /** moal_free_timer */
+ mlan_status(*moal_free_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_start_timer*/
+ mlan_status(*moal_start_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status(*moal_stop_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_init_lock */
+ mlan_status(*moal_init_lock) (IN t_void * pmoal_handle,
+ OUT t_void ** pplock);
+ /** moal_free_lock */
+ mlan_status(*moal_free_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_lock */
+ mlan_status(*moal_spin_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_unlock */
+ mlan_status(*moal_spin_unlock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_print */
+ t_void(*moal_print) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...);
+ /** moal_print_netintf */
+ t_void(*moal_print_netintf) (IN t_void * pmoal_handle,
+ IN t_u32 bss_index, IN t_u32 level);
+ /** moal_assert */
+ t_void(*moal_assert) (IN t_void * pmoal_handle, IN t_u32 cond);
+} mlan_callbacks, *pmlan_callbacks;
+
+/** Interrupt Mode SDIO */
+#define INT_MODE_SDIO 0
+/** Interrupt Mode GPIO */
+#define INT_MODE_GPIO 1
+
+/** Parameter unchanged, use MLAN default setting */
+#define MLAN_INIT_PARA_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define MLAN_INIT_PARA_ENABLED 1
+/** Parameter disabled, override MLAN default setting */
+#define MLAN_INIT_PARA_DISABLED 2
+
+/** mlan_device data structure */
+typedef struct _mlan_device
+{
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+#if defined(STA_SUPPORT)
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+#endif
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(IN pmlan_device pmdevice,
+ OUT t_void ** ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(IN t_void * pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter,
+ IN pmlan_fw_image pmfw);
+
+/** Custom data pass API */
+MLAN_API mlan_status mlan_set_init_param(IN t_void * pmlan_adapter,
+ IN pmlan_init_param pparam);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(IN t_void * pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(IN t_void * pmlan_adapter);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf);
+
+/** Packet Reception complete callback */
+MLAN_API mlan_status mlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+
+/** interrupt handler */
+MLAN_API t_void mlan_interrupt(IN t_void * pmlan_adapter);
+
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(IN t_void * pmlan_adapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** mlan select wmm queue */
+MLAN_API t_u8 mlan_select_wmm_queue(IN t_void * pmlan_adapter,
+ IN t_u8 bss_num, IN t_u8 tid);
+#endif /* !_MLAN_DECL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_fw.h b/drivers/net/wireless/sd8797/mlan/mlan_fw.h
new file mode 100644
index 000000000000..fda2e7285dfd
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_fw.h
@@ -0,0 +1,4672 @@
+/** @file mlan_fw.h
+ *
+ * @brief This file contains firmware specific defines.
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ * 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/27/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_FW_H_
+#define _MLAN_FW_H_
+
+/** Interface header length */
+#define INTF_HEADER_LEN 4
+
+/** Ethernet header */
+typedef struct
+{
+ /** Ethernet header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header length */
+ t_u16 h803_len;
+
+} Eth803Hdr_t;
+
+/** RFC 1042 header */
+typedef struct
+{
+ /** LLC DSAP */
+ t_u8 llc_dsap;
+ /** LLC SSAP */
+ t_u8 llc_ssap;
+ /** LLC CTRL */
+ t_u8 llc_ctrl;
+ /** SNAP OUI */
+ t_u8 snap_oui[3];
+ /** SNAP type */
+ t_u16 snap_type;
+
+} Rfc1042Hdr_t;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Rx packet header */
+typedef MLAN_PACK_START struct
+{
+ /** Etherner header */
+ Eth803Hdr_t eth803_hdr;
+ /** RFC 1042 header */
+ Rfc1042Hdr_t rfc1042_hdr;
+
+} MLAN_PACK_END RxPacketHdr_t;
+
+/** Rates supported in band B */
+#define B_SUPPORTED_RATES 5
+/** Rates supported in band G */
+#define G_SUPPORTED_RATES 9
+/** Rates supported in band BG */
+#define BG_SUPPORTED_RATES 13
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define A_SUPPORTED_RATES 9
+
+/** CapInfo Short Slot Time Disabled */
+//#define SHORT_SLOT_TIME_DISABLED(CapInfo) ((IEEEtypes_CapInfo_t)(CapInfo).short_slot_time = 0)
+#define SHORT_SLOT_TIME_DISABLED(CapInfo) (CapInfo &= ~MBIT(10))
+/** CapInfo Short Slot Time Enabled */
+#define SHORT_SLOT_TIME_ENABLED(CapInfo) (CapInfo |= MBIT(10))
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define HOSTCMD_SUPPORTED_RATES 14
+
+/** Rates supported in band N */
+#define N_SUPPORTED_RATES 3
+#ifdef STA_SUPPORT
+/** All bands (B, G, N) */
+#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN)
+#else
+/** All bands (B, G, A) */
+#define ALL_802_11_BANDS (BAND_B | BAND_G | BAND_A)
+#endif /* STA_SUPPORT */
+
+#ifdef STA_SUPPORT
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT (MBIT(8) | MBIT(9) | MBIT(10) | MBIT(11))
+#else
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT (MBIT(8) | MBIT(9) | MBIT(10))
+#endif /* STA_SUPPORT */
+/** Check if multiple bands support is enabled in firmware */
+#define IS_SUPPORT_MULTI_BANDS(_adapter) \
+ (_adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+/** Get default bands of the firmware */
+#define GET_FW_DEFAULT_BANDS(_adapter) \
+ ((_adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+
+extern t_u8 SupportedRates_B[B_SUPPORTED_RATES];
+extern t_u8 SupportedRates_G[G_SUPPORTED_RATES];
+extern t_u8 SupportedRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 SupportedRates_A[A_SUPPORTED_RATES];
+extern t_u8 SupportedRates_N[N_SUPPORTED_RATES];
+extern t_u8 AdhocRates_G[G_SUPPORTED_RATES];
+extern t_u8 AdhocRates_B[B_SUPPORTED_RATES];
+extern t_u8 AdhocRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 AdhocRates_A[A_SUPPORTED_RATES];
+
+/** Default auto deep sleep mode */
+#define DEFAULT_AUTO_DS_MODE MTRUE
+/** Default power save mode */
+#define DEFAULT_PS_MODE Wlan802_11PowerModePSP
+
+/** WEP Key index mask */
+#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
+
+/** Key information enabled */
+#define KEY_INFO_ENABLED 0x01
+/** KEY_TYPE_ID */
+typedef enum _KEY_TYPE_ID
+{
+ /** Key type : WEP */
+ KEY_TYPE_ID_WEP = 0,
+ /** Key type : TKIP */
+ KEY_TYPE_ID_TKIP,
+ /** Key type : AES */
+ KEY_TYPE_ID_AES,
+ KEY_TYPE_ID_WAPI,
+} KEY_TYPE_ID;
+
+/** Key Info flag for multicast key */
+#define KEY_INFO_MCAST_KEY 0x01
+/** Key Info flag for unicast key */
+#define KEY_INFO_UCAST_KEY 0x02
+
+/** KEY_INFO_WEP*/
+typedef enum _KEY_INFO_WEP
+{
+ KEY_INFO_WEP_MCAST = 0x01,
+ KEY_INFO_WEP_UNICAST = 0x02,
+ KEY_INFO_WEP_ENABLED = 0x04
+} KEY_INFO_WEP;
+
+/** KEY_INFO_TKIP */
+typedef enum _KEY_INFO_TKIP
+{
+ KEY_INFO_TKIP_MCAST = 0x01,
+ KEY_INFO_TKIP_UNICAST = 0x02,
+ KEY_INFO_TKIP_ENABLED = 0x04
+} KEY_INFO_TKIP;
+
+/** KEY_INFO_AES*/
+typedef enum _KEY_INFO_AES
+{
+ KEY_INFO_AES_MCAST = 0x01,
+ KEY_INFO_AES_UNICAST = 0x02,
+ KEY_INFO_AES_ENABLED = 0x04
+} KEY_INFO_AES;
+
+/** WPA AES key length */
+#define WPA_AES_KEY_LEN 16
+/** WPA TKIP key length */
+#define WPA_TKIP_KEY_LEN 32
+
+/** WAPI key length */
+#define WAPI_KEY_LEN 50
+/** KEY_INFO_WAPI*/
+typedef enum _KEY_INFO_WAPI
+{
+ KEY_INFO_WAPI_MCAST = 0x01,
+ KEY_INFO_WAPI_UNICAST = 0x02,
+ KEY_INFO_WAPI_ENABLED = 0x04
+} KEY_INFO_WAPI;
+
+/** Maximum ethernet frame length sans FCS */
+#define MV_ETH_FRAME_LEN 1514
+
+/** Length of SNAP header */
+#define MRVDRV_SNAP_HEADER_LEN 8
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES 100
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active when multiple interface is present */
+#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active. (polling the scratch register). */
+#define MAX_FIRMWARE_POLL_TRIES 100
+
+/** This is for firmware specific length */
+#define EXTRA_LEN 36
+
+/** Buffer size for ethernet Tx packets */
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
+
+/** Buffer size for ethernet Rx packets */
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(RxPD) \
+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+/* Macros in interface module */
+/** Firmware ready */
+#define FIRMWARE_READY 0xfedc
+
+/** Number of firmware blocks to transfer */
+#define FIRMWARE_TRANSFER_NBLOCK 2
+
+/** Enumeration definition*/
+/** WLAN_802_11_PRIVACY_FILTER */
+typedef enum _WLAN_802_11_PRIVACY_FILTER
+{
+ Wlan802_11PrivFilterAcceptAll,
+ Wlan802_11PrivFilter8021xWEP
+} WLAN_802_11_PRIVACY_FILTER;
+
+/** WLAN_802_11_WEP_STATUS */
+typedef enum _WLAN_802_11_WEP_STATUS
+{
+ Wlan802_11WEPEnabled,
+ Wlan802_11WEPDisabled,
+ Wlan802_11WEPKeyAbsent,
+ Wlan802_11WEPNotSupported
+} WLAN_802_11_WEP_STATUS;
+
+/** SNR calculation */
+#define CAL_SNR(RSSI, NF) ((t_s16)((t_s16)(RSSI)-(t_s16)(NF)))
+
+/** 2K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_2K 2048
+
+/** TLV type ID definition */
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+
+/** Terminating TLV Type */
+#define MRVL_TERMINATE_TLV_ID 0xffff
+
+/** TLV type : SSID */
+#define TLV_TYPE_SSID 0x0000
+/** TLV type : Rates */
+#define TLV_TYPE_RATES 0x0001
+/** TLV type : PHY FH */
+#define TLV_TYPE_PHY_FH 0x0002
+/** TLV type : PHY DS */
+#define TLV_TYPE_PHY_DS 0x0003
+/** TLV type : CF */
+#define TLV_TYPE_CF 0x0004
+/** TLV type : IBSS */
+#define TLV_TYPE_IBSS 0x0006
+
+/** TLV type : Domain */
+#define TLV_TYPE_DOMAIN 0x0007
+
+/** TLV type : Power constraint */
+#define TLV_TYPE_POWER_CONSTRAINT 0x0020
+
+/** TLV type : Power capability */
+#define TLV_TYPE_POWER_CAPABILITY 0x0021
+
+/** TLV type : Vendor Specific IE */
+#define TLV_TYPE_VENDOR_SPECIFIC_IE 0xdd
+
+/** TLV type : Key material */
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0x00) // 0x0100
+/** TLV type : Channel list */
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 0x01) // 0x0101
+/** TLV type : Number of probes */
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 0x02) // 0x0102
+/** TLV type : Beacon RSSI low */
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 0x04) // 0x0104
+/** TLV type : Beacon SNR low */
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 0x05) // 0x0105
+/** TLV type : Fail count */
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 0x06) // 0x0106
+/** TLV type : BCN miss */
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 0x07) // 0x0107
+/** TLV type : LED behavior */
+#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 0x09) // 0x0109
+/** TLV type : Passthrough */
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 0x0a) // 0x010a
+/** TLV type : Power TBL 2.4 Ghz */
+#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 0x0c) // 0x010c
+/** TLV type : Power TBL 5 GHz */
+#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 0x0d) // 0x010d
+/** TLV type : WMM queue status */
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 0x10) // 0x0110
+/** TLV type : Wildcard SSID */
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 0x12) // 0x0112
+/** TLV type : TSF timestamp */
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 0x13) // 0x0113
+/** TLV type : ARP filter */
+#define TLV_TYPE_ARP_FILTER (PROPRIETARY_TLV_BASE_ID + 0x15) // 0x0115
+/** TLV type : Beacon RSSI high */
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 0x16) // 0x0116
+/** TLV type : Beacon SNR high */
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 0x17) // 0x0117
+/** TLV type : Start BG scan later */
+#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 0x1e) // 0x011e
+/** TLV type: BG scan repeat count */
+#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 0xb0) // 0x01b0
+/** TLV type : Authentication type */
+#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 0x1f) // 0x011f
+/** TLV type : BSSID */
+#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 0x23) // 0x0123
+
+/** TLV type : Link Quality */
+#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 0x24) // 0x0124
+
+/** TLV type : Data RSSI low */
+#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 0x26) // 0x0126
+/** TLV type : Data SNR low */
+#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 0x27) // 0x0127
+/** TLV type : Data RSSI high */
+#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 0x28) // 0x0128
+/** TLV type : Data SNR high */
+#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 0x29) // 0x0129
+
+/** TLV type : Channel band list */
+#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 0x2a) // 0x012a
+
+/** TLV type : Passphrase */
+#define TLV_TYPE_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 0x3c) // 0x013c
+
+/** TLV type : Encryption Protocol TLV */
+#define TLV_TYPE_ENCRYPTION_PROTO (PROPRIETARY_TLV_BASE_ID + 0x40) // 0x0140
+/** TLV type : Cipher TLV */
+#define TLV_TYPE_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x42) // 0x0142
+/** TLV type : PMK */
+#define TLV_TYPE_PMK (PROPRIETARY_TLV_BASE_ID + 0x44) // 0x0144
+
+/** TLV type : BCN miss */
+#define TLV_TYPE_PRE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 0x49) // 0x0149
+
+/** TLV type: WAPI IE */
+#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 0x5e) // 0x015e
+
+/** TLV type: MGMT IE */
+#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 0x69) // 0x0169
+/** TLV type: MAX_MGMT_IE */
+#define TLV_TYPE_MAX_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 0xaa) // 0x01aa
+
+/** TLV type : HT Capabilities */
+#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 0x4a) // 0x014a
+/** TLV type : HT Information */
+#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 0x4b) // 0x014b
+/** TLV type : Secondary Channel Offset */
+#define TLV_SECONDARY_CHANNEL_OFFSET (PROPRIETARY_TLV_BASE_ID + 0x4c) // 0x014c
+/** TLV type : 20/40 BSS Coexistence */
+#define TLV_TYPE_2040BSS_COEXISTENCE (PROPRIETARY_TLV_BASE_ID + 0x4d) // 0x014d
+/** TLV type : Overlapping BSS Scan Parameters */
+#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM (PROPRIETARY_TLV_BASE_ID + 0x4e) // 0x014e
+/** TLV type : Extended capabilities */
+#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 0x4f) // 0x014f
+/** TLV type : Set of MCS values that STA desires to use within the BSS */
+#define TLV_TYPE_HT_OPERATIONAL_MCS_SET (PROPRIETARY_TLV_BASE_ID + 0x50) // 0x0150
+/** TLV type : RXBA_SYNC */
+#define TLV_TYPE_RXBA_SYNC (PROPRIETARY_TLV_BASE_ID + 0x99) // 0x0199
+/** ADDBA TID mask */
+#define ADDBA_TID_MASK (MBIT(2) | MBIT(3) | MBIT(4) | MBIT(5))
+/** DELBA TID mask */
+#define DELBA_TID_MASK (MBIT(12) | MBIT(13) | MBIT(14) | MBIT(15))
+/** ADDBA Starting Sequence Number Mask */
+#define SSN_MASK 0xfff0
+
+/** Block Ack result status */
+/** Block Ack Result : Success */
+#define BA_RESULT_SUCCESS 0x0
+/** Block Ack Result : Execution failure */
+#define BA_RESULT_FAILURE 0x1
+/** Block Ack Result : Timeout */
+#define BA_RESULT_TIMEOUT 0x2
+/** Block Ack Result : Data invalid */
+#define BA_RESULT_DATA_INVALID 0x3
+
+/** Get the baStatus (NOT_SETUP, COMPLETE, IN_PROGRESS)
+ * in Tx BA stream table */
+#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
+
+/** An AMPDU/AMSDU could be disallowed for certain TID. 0xff means
+ * no aggregation is enabled for the assigned TID */
+#define BA_STREAM_NOT_ALLOWED 0xff
+
+/** Test if 11n is enabled by checking the HTCap IE */
+#define IS_11N_ENABLED(priv) ((priv->config_bands & BAND_GN ||priv->config_bands & BAND_AN) \
+ && priv->curr_bss_params.bss_descriptor.pht_cap)
+/** Find out if we are the initiator or not */
+#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) & \
+ MBIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
+
+/** 4K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_4K 4096
+/** 8K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_8K 8192
+/** Max Rx AMPDU Size */
+#define MAX_RX_AMPDU_SIZE_64K 0x03
+/** Non green field station */
+#define NON_GREENFIELD_STAS 0x04
+
+/** Greenfield support */
+#define HWSPEC_GREENFIELD_SUPP MBIT(29)
+/** RX STBC support */
+#define HWSPEC_RXSTBC_SUPP MBIT(26)
+/** ShortGI @ 40Mhz support */
+#define HWSPEC_SHORTGI40_SUPP MBIT(24)
+/** ShortGI @ 20Mhz support */
+#define HWSPEC_SHORTGI20_SUPP MBIT(23)
+/** Channel width 40Mhz support */
+#define HWSPEC_CHANBW40_SUPP MBIT(17)
+/** 40Mhz intolarent enable */
+#define CAPINFO_40MHZ_INTOLARENT MBIT(8)
+
+/** Default 11n capability mask for 2.4GHz */
+#define DEFAULT_11N_CAP_MASK_BG (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP)
+/** Default 11n capability mask for 5GHz */
+#define DEFAULT_11N_CAP_MASK_A (HWSPEC_CHANBW40_SUPP | HWSPEC_SHORTGI20_SUPP | \
+ HWSPEC_SHORTGI40_SUPP | HWSPEC_RXSTBC_SUPP)
+/** Bits to ignore in hw_dev_cap as these bits are set in get_hw_spec */
+#define IGN_HW_DEV_CAP (CAPINFO_40MHZ_INTOLARENT)
+
+/** HW_SPEC FwCapInfo */
+#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & MBIT(11))
+
+/** HW_SPEC Dot11nDevCap : MAX AMSDU supported */
+#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & MBIT(31))
+/** HW_SPEC Dot11nDevCap : Beamforming support */
+#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & MBIT(30))
+/** HW_SPEC Dot11nDevCap : Green field support */
+#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & MBIT(29))
+/** HW_SPEC Dot11nDevCap : AMPDU support */
+#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & MBIT(28))
+/** HW_SPEC Dot11nDevCap : MIMO PS support */
+#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & MBIT(27))
+/** HW_SPEC Dot11nDevCap : Rx STBC support */
+#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(26))
+/** HW_SPEC Dot11nDevCap : Tx STBC support */
+#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(25))
+/** HW_SPEC Dot11nDevCap : Short GI @ 40Mhz support */
+#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & MBIT(24))
+/** HW_SPEC Dot11nDevCap : Short GI @ 20Mhz support */
+#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & MBIT(23))
+/** HW_SPEC Dot11nDevCap : Rx LDPC support */
+#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & MBIT(22))
+/** HW_SPEC Dot11nDevCap : Delayed ACK */
+#define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03))
+/** HW_SPEC Dot11nDevCap : Immediate ACK */
+#define GET_IMMEDIATEBACK(Dot11nDevCap) (((Dot11nDevCap >> 18) & 0x03))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 40Mhz support */
+#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & MBIT(17))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 20Mhz support */
+#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & MBIT(16))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 10Mhz support */
+#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & MBIT(15))
+/** Dot11nUsrCap : 40Mhz intolarance enabled */
+#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & MBIT(8))
+/** HW_SPEC Dot11nDevCap : Rx AntennaD support */
+#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(7))
+/** HW_SPEC Dot11nDevCap : Rx AntennaC support */
+#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(6))
+/** HW_SPEC Dot11nDevCap : Rx AntennaB support */
+#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(5))
+/** HW_SPEC Dot11nDevCap : Rx AntennaA support */
+#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(4))
+/** HW_SPEC Dot11nDevCap : Tx AntennaD support */
+#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(3))
+/** HW_SPEC Dot11nDevCap : Tx AntennaC support */
+#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(2))
+/** HW_SPEC Dot11nDevCap : Tx AntennaB support */
+#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(1))
+/** HW_SPEC Dot11nDevCap : Tx AntennaA support */
+#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(0))
+
+/** HW_SPEC Dot11nDevCap : Set support of channel bw @ 40Mhz */
+#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= MBIT(17))
+/** HW_SPEC Dot11nDevCap : Reset support of channel bw @ 40Mhz */
+#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~MBIT(17))
+
+/** DevMCSSupported : Tx MCS supported */
+#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4)
+/** DevMCSSupported : Rx MCS supported */
+#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
+
+/** GET HTCapInfo : Supported Channel BW */
+#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & MBIT(1))
+/** GET HTCapInfo : Support for Greenfield */
+#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & MBIT(4))
+/** GET HTCapInfo : Support for Short GI @ 20Mhz */
+#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & MBIT(5))
+/** GET HTCapInfo : Support for Short GI @ 40Mhz */
+#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & MBIT(6))
+/** GET HTCapInfo : Support for Tx STBC */
+#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & MBIT(7))
+
+/** GET HTCapInfo : Support for Rx STBC */
+#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03)
+/** GET HTCapInfo : Support for Delayed ACK */
+#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & MBIT(10))
+/** GET HTCapInfo : Support for Max AMSDU */
+#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & MBIT(11))
+
+/** SET HTCapInfo : Set support for LDPC coding capability */
+#define SETHT_LDPCCODINGCAP(HTCapInfo) (HTCapInfo |= MBIT(0))
+/** SET HTCapInfo : Set support for Channel BW */
+#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= MBIT(1))
+/** SET HTCapInfo : Set support for Greenfield */
+#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= MBIT(4))
+/** SET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= MBIT(5))
+/** SET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= MBIT(6))
+/** SET HTCapInfo : Set support for Tx STBC */
+#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= MBIT(7))
+/** SET HTCapInfo : Set support for Rx STBC */
+#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8))
+/** SET HTCapInfo : Set support for delayed block ack */
+#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= MBIT(10))
+/** SET HTCapInfo : Set support for Max size AMSDU */
+#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= MBIT(11))
+/** SET HTCapInfo : Set support for DSSS/CCK Rates @ 40Mhz */
+#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= MBIT(12))
+/** SET HTCapInfo : Enable 40Mhz Intolarence */
+#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= MBIT(14))
+
+/** RESET HTCapInfo : Set support for LDPC coding capability */
+#define RESETHT_LDPCCODINGCAP(HTCapInfo) (HTCapInfo &= ~MBIT(0))
+/** RESET HTCapInfo : Set support for Channel BW */
+#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~MBIT(1))
+/** RESET HTCapInfo : Set support for Greenfield */
+#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~MBIT(4))
+/** RESET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~MBIT(5))
+/** RESET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~MBIT(6))
+/** RESET HTCapInfo : Set support for Tx STBC */
+#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~MBIT(7))
+/** RESET HTCapInfo : Set support for Rx STBC */
+#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8))
+/** RESET HTCapInfo : Set support for delayed block ack */
+#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~MBIT(10))
+/** RESET HTCapInfo : Set support for Max size AMSDU */
+#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~MBIT(11))
+/** RESET HTCapInfo : Disable 40Mhz Intolarence */
+#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~MBIT(14))
+/** RESET HTExtCap : Clear RD Responder bit */
+#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~MBIT(11))
+/** SET MCS32 */
+#define SETHT_MCS32(x) (x[4] |= 1)
+/** Set mcs set defined bit */
+#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1)
+/** Set the highest Rx data rate */
+#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(t_u16 *) (x + 10)) = y)
+/** AMPDU factor size */
+#define AMPDU_FACTOR_64K 0x03
+/** Set AMPDU size in A-MPDU paramter field */
+#define SETAMPDU_SIZE(x, y) do { \
+ x = x & ~0x03; \
+ x |= y & 0x03; \
+} while (0) \
+/** Set AMPDU spacing in A-MPDU paramter field */
+#define SETAMPDU_SPACING(x, y) do { \
+ x = x & ~0x1c; \
+ x |= (y & 0x07) << 2; \
+} while (0) \
+
+/** RadioType : Support for Band A */
+#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & MBIT(10))
+/** RadioType : Support for 40Mhz channel BW */
+#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & MBIT(2))
+/** RadioType : Set support 40Mhz channel */
+#define SET_CHANWIDTH40(Field2) (Field2 |= MBIT(2))
+/** RadioType : Reset support 40Mhz channel */
+#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(MBIT(0) | MBIT(1) | MBIT(2)))
+/** RadioType : Get secondary channel */
+#define GET_SECONDARYCHAN(Field2) (Field2 & (MBIT(0) | MBIT(1)))
+/** RadioType : Set secondary channel */
+#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
+
+/** LLC/SNAP header len */
+#define LLC_SNAP_LEN 8
+
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_DROP_PATTERN (PROPRIETARY_TLV_BASE_ID + 0x51) // 0x0151
+/** TLV type : Rate drop pattern */
+#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 0x52) // 0x0152
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 0x53) // 0x0153
+
+/** TLV type : Power group */
+#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 0x54) // 0x0154
+
+/** Modulation class for DSSS Rates */
+#define MOD_CLASS_HR_DSSS 0x03
+/** Modulation class for OFDM Rates */
+#define MOD_CLASS_OFDM 0x07
+/** Modulation class for HT Rates */
+#define MOD_CLASS_HT 0x08
+/** HT bandwidth 20 MHz */
+#define HT_BW_20 0
+/** HT bandwidth 40 MHz */
+#define HT_BW_40 1
+
+/** TLV type : Scan Response */
+#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 0x56) // 0x0156
+/** TLV type : Scan Response Stats */
+#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 0x57) // 0x0157
+
+/** TLV type : 11h Basic Rpt */
+#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 0x5b) // 0x015b
+
+/** TLV type : Action frame */
+#define TLV_TYPE_IEEE_ACTION_FRAME (PROPRIETARY_TLV_BASE_ID + 0x8c) // 0x018c
+
+/** Firmware Host Command ID Constants */
+/** Host Command ID : Get hardware specifications */
+#define HostCmd_CMD_GET_HW_SPEC 0x0003
+/** Host Command ID : 802.11 scan */
+#define HostCmd_CMD_802_11_SCAN 0x0006
+/** Host Command ID : 802.11 get log */
+#define HostCmd_CMD_802_11_GET_LOG 0x000b
+/** Host Command ID : MAC multicast address */
+#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
+/** Host Command ID : 802.11 EEPROM access */
+#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
+/** Host Command ID : 802.11 associate */
+#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
+
+/** Host Command ID : 802.11 SNMP MIB */
+#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
+/** Host Command ID : MAC register access */
+#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
+/** Host Command ID : BBP register access */
+#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
+/** Host Command ID : RF register access */
+#define HostCmd_CMD_RF_REG_ACCESS 0x001b
+
+/** Host Command ID : 802.11 radio control */
+#define HostCmd_CMD_802_11_RADIO_CONTROL 0x001c
+/** Host Command ID : 802.11 RF channel */
+#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
+/** Host Command ID : 802.11 RF Tx power */
+#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e
+
+/** Host Command ID : 802.11 RF antenna */
+#define HostCmd_CMD_802_11_RF_ANTENNA 0x0020
+
+/** Host Command ID : 802.11 deauthenticate */
+#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
+/** Host Command ID : MAC control */
+#define HostCmd_CMD_MAC_CONTROL 0x0028
+/** Host Command ID : 802.11 Ad-Hoc start */
+#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
+/** Host Command ID : 802.11 Ad-Hoc join */
+#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
+
+/** Host Command ID : 802.11 key material */
+#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
+
+/** Host Command ID : 802.11 Ad-Hoc stop */
+#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
+
+/** Host Command ID : 802.22 MAC address */
+#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
+
+/** Host Command ID : WMM Traffic Stream Status */
+#define HostCmd_CMD_WMM_TS_STATUS 0x005d
+
+/** Host Command ID : 802.11 D domain information */
+#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
+
+/** Host Command ID : 802.11 TPC information */
+#define HostCmd_CMD_802_11_TPC_INFO 0x005f
+/** Host Command ID : 802.11 TPC adapt req */
+#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060
+/** Host Command ID : 802.11 channel SW ann */
+#define HostCmd_CMD_802_11_CHAN_SW_ANN 0x0061
+
+/** Host Command ID : Measurement request */
+#define HostCmd_CMD_MEASUREMENT_REQUEST 0x0062
+/** Host Command ID : Measurement report */
+#define HostCmd_CMD_MEASUREMENT_REPORT 0x0063
+
+/** Host Command ID : 802.11 sleep parameters */
+#define HostCmd_CMD_802_11_SLEEP_PARAMS 0x0066
+
+/** Host Command ID : 802.11 sleep period */
+#define HostCmd_CMD_802_11_SLEEP_PERIOD 0x0068
+
+/** Host Command ID: 802.11 BG scan config */
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
+/** Host Command ID : 802.11 BG scan query */
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
+
+/** Host Command ID : WMM ADDTS req */
+#define HostCmd_CMD_WMM_ADDTS_REQ 0x006E
+/** Host Command ID : WMM DELTS req */
+#define HostCmd_CMD_WMM_DELTS_REQ 0x006F
+/** Host Command ID : WMM queue configuration */
+#define HostCmd_CMD_WMM_QUEUE_CONFIG 0x0070
+/** Host Command ID : 802.11 get status */
+#define HostCmd_CMD_WMM_GET_STATUS 0x0071
+
+/** Host Command ID : 802.11 subscribe event */
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
+
+/** Host Command ID : 802.11 Tx rate query */
+#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
+
+/** Host Command ID : WMM queue stats */
+#define HostCmd_CMD_WMM_QUEUE_STATS 0x0081
+
+/** Host Command ID : 802.11 IBSS coalescing status */
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+
+/** Host Command ID : Memory access */
+#define HostCmd_CMD_MEM_ACCESS 0x0086
+
+/** Host Command ID : SDIO GPIO interrupt configuration */
+#define HostCmd_CMD_SDIO_GPIO_INT_CONFIG 0x0088
+
+#ifdef MFG_CMD_SUPPORT
+/** Host Command ID : Mfg command */
+#define HostCmd_CMD_MFG_COMMAND 0x0089
+#endif
+/** Host Command ID : Inactivity timeout ext */
+#define HostCmd_CMD_INACTIVITY_TIMEOUT_EXT 0x008a
+
+/** Host Command ID : DBGS configuration */
+#define HostCmd_CMD_DBGS_CFG 0x008b
+/** Host Command ID : Get memory */
+#define HostCmd_CMD_GET_MEM 0x008c
+
+/** Host Command ID : Cal data dnld */
+#define HostCmd_CMD_CFG_DATA 0x008f
+
+/** Host Command ID : SDIO pull control */
+#define HostCmd_CMD_SDIO_PULL_CTRL 0x0093
+
+/** Host Command ID : ECL system clock configuration */
+#define HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG 0x0094
+
+/** Host Command ID : Extended version */
+#define HostCmd_CMD_VERSION_EXT 0x0097
+
+/** Host Command ID : MEF configuration */
+#define HostCmd_CMD_MEF_CFG 0x009a
+
+/** Host Command ID : 802.11 RSSI INFO*/
+#define HostCmd_CMD_RSSI_INFO 0x00a4
+
+/** Host Command ID : Function initialization */
+#define HostCmd_CMD_FUNC_INIT 0x00a9
+/** Host Command ID : Function shutdown */
+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+
+/** Host Command ID : Channel report request */
+#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd
+
+/** Host Command ID: SUPPLICANT_PMK */
+#define HostCmd_CMD_SUPPLICANT_PMK 0x00c4
+/** Host Command ID: SUPPLICANT_PROFILE */
+#define HostCmd_CMD_SUPPLICANT_PROFILE 0x00c5
+
+/** Host Command ID : Add Block Ack Request */
+#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_CFG 0x00cd
+/** Host Command ID : Add Block Ack Response */
+#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_DELBA 0x00d0
+/** Host Command ID: Configure Tx Buf size */
+#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+/** Host Command ID: AMSDU Aggr Ctrl */
+#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
+/** Host Command ID: Configure TX Beamforming capability */
+#define HostCmd_CMD_TX_BF_CFG 0x0104
+
+/** Host Command ID : 802.11 TX power configuration */
+#define HostCmd_CMD_TXPWR_CFG 0x00d1
+
+/** Host Command ID : Soft Reset */
+#define HostCmd_CMD_SOFT_RESET 0x00d5
+
+/** Host Command ID : 802.11 b/g/n rate configration */
+#define HostCmd_CMD_TX_RATE_CFG 0x00d6
+
+/** Host Command ID : Enhanced PS mode */
+#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
+
+/** Host command action : Host sleep configuration */
+#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
+
+/** Host Command ID : CAU register access */
+#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
+
+/** Host Command ID : mgmt IE list */
+#define HostCmd_CMD_MGMT_IE_LIST 0x00f2
+
+/** Host Command ID : Extended scan support */
+#define HostCmd_CMD_802_11_SCAN_EXT 0x0107
+
+/** Host Command ID : Forward mgmt frame */
+#define HostCmd_CMD_RX_MGMT_IND 0x010c
+
+/** Host Command ID : Set BSS_MODE */
+#define HostCmd_CMD_SET_BSS_MODE 0x00f7
+
+#ifdef UAP_SUPPORT
+/** Host Command id: SYS_INFO */
+#define HOST_CMD_APCMD_SYS_INFO 0x00ae
+/** Host Command id: sys_reset */
+#define HOST_CMD_APCMD_SYS_RESET 0x00af
+/** Host Command id: SYS_CONFIGURE */
+#define HOST_CMD_APCMD_SYS_CONFIGURE 0x00b0
+/** Host Command id: BSS_START */
+#define HOST_CMD_APCMD_BSS_START 0x00b1
+/** Host Command id: BSS_STOP */
+#define HOST_CMD_APCMD_BSS_STOP 0x00b2
+/** Host Command id: sta_list */
+#define HOST_CMD_APCMD_STA_LIST 0x00b3
+/** Host Command id: STA_DEAUTH */
+#define HOST_CMD_APCMD_STA_DEAUTH 0x00b5
+
+#endif /* UAP_SUPPORT */
+
+/** Host Command ID: Tx data pause */
+#define HostCmd_CMD_CFG_TX_DATA_PAUSE 0x0103
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Host Command ID: WIFI_DIRECT_MODE_CONFIG */
+#define HOST_CMD_WIFI_DIRECT_MODE_CONFIG 0x00eb
+/** Host Command ID: Remain On Channel */
+#define HostCmd_CMD_802_11_REMAIN_ON_CHANNEL 0x010d
+#endif
+
+/** Host Command ID : OTP user data */
+#define HostCmd_CMD_OTP_READ_USER_DATA 0x0114
+
+/** Enhanced PS modes */
+typedef enum _ENH_PS_MODES
+{
+ GET_PS = 0,
+ SLEEP_CONFIRM = 5,
+ DIS_AUTO_PS = 0xfe,
+ EN_AUTO_PS = 0xff,
+} ENH_PS_MODES;
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT 0x8000
+
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET 0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** General purpose action : Get_Current */
+#define HostCmd_ACT_GEN_GET_CURRENT 0x0003
+/** General purpose action : Remove */
+#define HostCmd_ACT_GEN_REMOVE 0x0004
+
+/** Host command action : Set Rx */
+#define HostCmd_ACT_SET_RX 0x0001
+/** Host command action : Set Tx */
+#define HostCmd_ACT_SET_TX 0x0002
+/** Host command action : Set both Rx and Tx */
+#define HostCmd_ACT_SET_BOTH 0x0003
+/** Host command action : Get Rx */
+#define HostCmd_ACT_GET_RX 0x0004
+/** Host command action : Get Tx */
+#define HostCmd_ACT_GET_TX 0x0008
+/** Host command action : Get both Rx and Tx */
+#define HostCmd_ACT_GET_BOTH 0x000c
+
+/** General Result Code*/
+/** General result code OK */
+#define HostCmd_RESULT_OK 0x0000
+/** Genenral error */
+#define HostCmd_RESULT_ERROR 0x0001
+/** Command is not valid */
+#define HostCmd_RESULT_NOT_SUPPORT 0x0002
+/** Command is pending */
+#define HostCmd_RESULT_PENDING 0x0003
+/** System is busy (command ignored) */
+#define HostCmd_RESULT_BUSY 0x0004
+/** Data buffer is not big enough */
+#define HostCmd_RESULT_PARTIAL_DATA 0x0005
+
+/* Define action or option for HostCmd_CMD_MAC_CONTROL */
+/** MAC action : Rx on */
+#define HostCmd_ACT_MAC_RX_ON 0x0001
+/** MAC action : Tx on */
+#define HostCmd_ACT_MAC_TX_ON 0x0002
+/** MAC action : WEP enable */
+#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
+/** MAC action : EthernetII enable */
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
+/** MAC action : Promiscous mode enable */
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+/** MAC action : All multicast enable */
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+/** MAC action : RTS/CTS enable */
+#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200
+/** MAC action : Strict protection enable */
+#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
+/** MAC action : Force 11n protection disable */
+#define HostCmd_ACT_MAC_FORCE_11N_PROTECTION_OFF 0x0800
+/** MAC action : Ad-Hoc G protection on */
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : BSS */
+#define HostCmd_BSS_MODE_BSS 0x0001
+/** Scan type : IBSS */
+#define HostCmd_BSS_MODE_IBSS 0x0002
+/** Scan type : Any */
+#define HostCmd_BSS_MODE_ANY 0x0003
+
+/* Radio type definitions for the channel TLV */
+/** Radio type BG */
+#define HostCmd_SCAN_RADIO_TYPE_BG 0
+/** Radio type A */
+#define HostCmd_SCAN_RADIO_TYPE_A 1
+
+/** Define bitmap conditions for HOST_SLEEP_CFG : GPIO FF */
+#define HOST_SLEEP_CFG_GPIO_FF 0xff
+/** Define bitmap conditions for HOST_SLEEP_CFG : GAP FF */
+#define HOST_SLEEP_CFG_GAP_FF 0xff
+
+/** Buffer Constants */
+/** Number of command buffers */
+#define MRVDRV_NUM_OF_CMD_BUFFER 20
+/** Size of command buffer */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+/** Maximum number of BSS Descriptors */
+#define MRVDRV_MAX_BSSID_LIST 64
+
+/** Host command flag in command */
+#define CMD_F_HOSTCMD (1 << 0)
+/** command cancel flag in command */
+#define CMD_F_CANCELED (1 << 1)
+
+/** Host Command ID bit mask (bit 11:0) */
+#define HostCmd_CMD_ID_MASK 0x0fff
+
+/** Host Command Sequence number mask (bit 7:0) */
+#define HostCmd_SEQ_NUM_MASK 0x00ff
+
+/** Host Command BSS number mask (bit 11:8) */
+#define HostCmd_BSS_NUM_MASK 0x0f00
+
+/** Host Command BSS type mask (bit 15:12) */
+#define HostCmd_BSS_TYPE_MASK 0xf000
+
+/** Set BSS information to Host Command */
+#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) \
+ (((seq) & 0x00ff) | \
+ (((num) & 0x000f) << 8)) | \
+ (((type) & 0x000f) << 12)
+
+/** Get Sequence Number from Host Command (bit 7:0) */
+#define HostCmd_GET_SEQ_NO(seq) \
+ ((seq) & HostCmd_SEQ_NUM_MASK)
+
+/** Get BSS number from Host Command (bit 11:8) */
+#define HostCmd_GET_BSS_NO(seq) \
+ (((seq) & HostCmd_BSS_NUM_MASK) >> 8)
+
+/** Get BSS type from Host Command (bit 15:12) */
+#define HostCmd_GET_BSS_TYPE(seq) \
+ (((seq) & HostCmd_BSS_TYPE_MASK) >> 12)
+
+/** Card Event definition : Dummy host wakeup signal */
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
+/** Card Event definition : Link lost */
+#define EVENT_LINK_LOST 0x00000003
+/** Card Event definition : Link sensed */
+#define EVENT_LINK_SENSED 0x00000004
+/** Card Event definition : MIB changed */
+#define EVENT_MIB_CHANGED 0x00000006
+/** Card Event definition : Init done */
+#define EVENT_INIT_DONE 0x00000007
+/** Card Event definition : Deauthenticated */
+#define EVENT_DEAUTHENTICATED 0x00000008
+/** Card Event definition : Disassociated */
+#define EVENT_DISASSOCIATED 0x00000009
+/** Card Event definition : Power save awake */
+#define EVENT_PS_AWAKE 0x0000000a
+/** Card Event definition : Power save sleep */
+#define EVENT_PS_SLEEP 0x0000000b
+/** Card Event definition : MIC error multicast */
+#define EVENT_MIC_ERR_MULTICAST 0x0000000d
+/** Card Event definition : MIC error unicast */
+#define EVENT_MIC_ERR_UNICAST 0x0000000e
+
+/** Card Event definition : Ad-Hoc BCN lost */
+#define EVENT_ADHOC_BCN_LOST 0x00000011
+
+/** Card Event definition : Stop Tx */
+#define EVENT_STOP_TX 0x00000013
+/** Card Event definition : Start Tx */
+#define EVENT_START_TX 0x00000014
+/** Card Event definition : Channel switch */
+#define EVENT_CHANNEL_SWITCH 0x00000015
+
+/** Card Event definition : MEAS report ready */
+#define EVENT_MEAS_REPORT_RDY 0x00000016
+
+/** Card Event definition : WMM status change */
+#define EVENT_WMM_STATUS_CHANGE 0x00000017
+
+/** Card Event definition : BG scan report */
+#define EVENT_BG_SCAN_REPORT 0x00000018
+
+/** Card Event definition : Beacon RSSI low */
+#define EVENT_RSSI_LOW 0x00000019
+/** Card Event definition : Beacon SNR low */
+#define EVENT_SNR_LOW 0x0000001a
+/** Card Event definition : Maximum fail */
+#define EVENT_MAX_FAIL 0x0000001b
+/** Card Event definition : Beacon RSSI high */
+#define EVENT_RSSI_HIGH 0x0000001c
+/** Card Event definition : Beacon SNR high */
+#define EVENT_SNR_HIGH 0x0000001d
+
+/** Card Event definition : IBSS coalsced */
+#define EVENT_IBSS_COALESCED 0x0000001e
+
+/** Card Event definition : Data RSSI low */
+#define EVENT_DATA_RSSI_LOW 0x00000024
+/** Card Event definition : Data SNR low */
+#define EVENT_DATA_SNR_LOW 0x00000025
+/** Card Event definition : Data RSSI high */
+#define EVENT_DATA_RSSI_HIGH 0x00000026
+/** Card Event definition : Data SNR high */
+#define EVENT_DATA_SNR_HIGH 0x00000027
+
+/** Card Event definition : Link Quality */
+#define EVENT_LINK_QUALITY 0x00000028
+
+/** Card Event definition : Port release event */
+#define EVENT_PORT_RELEASE 0x0000002b
+
+/** Card Event definition : Pre-Beacon Lost */
+#define EVENT_PRE_BEACON_LOST 0x00000031
+
+/** Card Event definition : Add BA event */
+#define EVENT_ADDBA 0x00000033
+/** Card Event definition : Del BA event */
+#define EVENT_DELBA 0x00000034
+/** Card Event definition: BA stream timeout*/
+#define EVENT_BA_STREAM_TIMEOUT 0x00000037
+
+/** Card Event definition : AMSDU aggr control */
+#define EVENT_AMSDU_AGGR_CTRL 0x00000042
+
+/** Card Event definition: WEP ICV error */
+#define EVENT_WEP_ICV_ERR 0x00000046
+
+/** Card Event definition : Host sleep enable */
+#define EVENT_HS_ACT_REQ 0x00000047
+
+/** Card Event definition : BW changed */
+#define EVENT_BW_CHANGE 0x00000048
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** WIFIDIRECT generic event */
+#define EVENT_WIFIDIRECT_GENERIC_EVENT 0x00000049
+/** WIFIDIRECT service discovery event */
+#define EVENT_WIFIDIRECT_SERVICE_DISCOVERY 0x0000004a
+/** Remain on Channel expired event */
+#define EVENT_REMAIN_ON_CHANNEL_EXPIRED 0x0000005f
+#endif
+
+/** Card Event definition: Channel switch pending announcment */
+#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
+
+/** Event definition: Radar Detected by card */
+#define EVENT_RADAR_DETECTED 0x00000053
+
+/** Event definition: Radar Detected by card */
+#define EVENT_CHANNEL_REPORT_RDY 0x00000054
+
+/** Event definition: Scan results through event */
+#define EVENT_EXT_SCAN_REPORT 0x00000058
+
+/** Event definition: RXBA_SYNC */
+#define EVENT_RXBA_SYNC 0x00000059
+
+#ifdef UAP_SUPPORT
+/** Event ID: STA deauth */
+#define EVENT_MICRO_AP_STA_DEAUTH 0x0000002c
+/** Event ID: STA assoicated */
+#define EVENT_MICRO_AP_STA_ASSOC 0x0000002d
+/** Event ID: BSS started */
+#define EVENT_MICRO_AP_BSS_START 0x0000002e
+/** Event ID: BSS idle event */
+#define EVENT_MICRO_AP_BSS_IDLE 0x00000043
+/** Event ID: BSS active event */
+#define EVENT_MICRO_AP_BSS_ACTIVE 0x00000044
+
+#endif /* UAP_SUPPORT */
+
+/** Event ID: TX data pause event */
+#define EVENT_TX_DATA_PAUSE 0x00000055
+
+/** Event ID mask */
+#define EVENT_ID_MASK 0xffff
+
+/** BSS number mask */
+#define BSS_NUM_MASK 0xf
+
+/** Get BSS number from event cause (bit 23:16) */
+#define EVENT_GET_BSS_NUM(event_cause) \
+ (((event_cause) >> 16) & BSS_NUM_MASK)
+
+/** Get BSS type from event cause (bit 31:24) */
+#define EVENT_GET_BSS_TYPE(event_cause) \
+ (((event_cause) >> 24) & 0x00ff)
+
+/** Event_WEP_ICV_ERR structure */
+typedef MLAN_PACK_START struct _Event_WEP_ICV_ERR
+{
+ /** Reason code */
+ t_u16 reason_code;
+ /** Source MAC address */
+ t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** WEP decryption used key */
+ t_u8 wep_key_index;
+ /** WEP key length */
+ t_u8 wep_key_length;
+ /** WEP key */
+ t_u8 key[MAX_WEP_KEY_SIZE];
+} MLAN_PACK_END Event_WEP_ICV_ERR;
+
+/** WLAN_802_11_FIXED_IEs */
+typedef MLAN_PACK_START struct _WLAN_802_11_FIXED_IEs
+{
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** Capabilities*/
+ t_u16 capabilities;
+} MLAN_PACK_END WLAN_802_11_FIXED_IEs;
+
+/** WLAN_802_11_VARIABLE_IEs */
+typedef MLAN_PACK_START struct _WLAN_802_11_VARIABLE_IEs
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 length;
+ /** IE data */
+ t_u8 data[1];
+} MLAN_PACK_END WLAN_802_11_VARIABLE_IEs;
+
+/** TLV related data structures*/
+/** MrvlIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlIEtypesHeader
+{
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} MLAN_PACK_END MrvlIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Data_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[1];
+} MLAN_PACK_END MrvlIEtypes_Data_t;
+
+/** Bit mask for TxPD status field for null packet */
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+/** Bit mask for TxPD status field for last packet */
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Packet type: 802.11 */
+#define PKT_TYPE_802DOT11 0x05
+#define PKT_TYPE_MGMT_FRAME 0xE5
+/** Packet type: AMSDU */
+#define PKT_TYPE_AMSDU 0xE6
+/** Packet type: BAR */
+#define PKT_TYPE_BAR 0xE7
+/** Packet type: debugging */
+#define PKT_TYPE_DEBUG 0xEF
+
+/** TxPD descriptor */
+typedef MLAN_PACK_START struct _TxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Tx packet length */
+ t_u16 tx_pkt_length;
+ /** Tx packet offset */
+ t_u16 tx_pkt_offset;
+ /** Tx packet type */
+ t_u16 tx_pkt_type;
+ /** Tx Control */
+ t_u32 tx_control;
+ /** Pkt Priority */
+ t_u8 priority;
+ /** Transmit Pkt Flags*/
+ t_u8 flags;
+ /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+ t_u8 pkt_delay_2ms;
+ /** Reserved */
+ t_u8 reserved1;
+} MLAN_PACK_END TxPD, *PTxPD;
+
+/** RxPD Descriptor */
+typedef MLAN_PACK_START struct _RxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Rx Packet Length */
+ t_u16 rx_pkt_length;
+ /** Rx Pkt offset */
+ t_u16 rx_pkt_offset;
+ /** Rx packet type */
+ t_u16 rx_pkt_type;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Packet Priority */
+ t_u8 priority;
+ /** Rx Packet Rate */
+ t_u8 rx_rate;
+ /** SNR */
+ t_s8 snr;
+ /** Noise Floor */
+ t_s8 nf;
+ /** Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ t_u8 ht_info;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END RxPD, *PRxPD;
+
+#ifdef UAP_SUPPORT
+/** TxPD descriptor */
+typedef MLAN_PACK_START struct _UapTxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Tx packet length */
+ t_u16 tx_pkt_length;
+ /** Tx packet offset */
+ t_u16 tx_pkt_offset;
+ /** Tx packet type */
+ t_u16 tx_pkt_type;
+ /** Tx Control */
+ t_u32 tx_control;
+ /** Pkt Priority */
+ t_u8 priority;
+ /** Transmit Pkt Flags*/
+ t_u8 flags;
+ /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+ t_u8 pkt_delay_2ms;
+ /** Reserved */
+ t_u8 reserved1;
+ /** Reserved */
+ t_u32 reserved;
+} MLAN_PACK_END UapTxPD, *PUapTxPD;
+
+/** RxPD Descriptor */
+typedef MLAN_PACK_START struct _UapRxPD
+{
+ /** BSS Type */
+ t_u8 bss_type;
+ /** BSS number*/
+ t_u8 bss_num;
+ /** Rx packet length */
+ t_u16 rx_pkt_length;
+ /** Rx packet offset */
+ t_u16 rx_pkt_offset;
+ /** Rx packet type */
+ t_u16 rx_pkt_type;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Packet Priority */
+ t_u8 priority;
+ /** reserved */
+ t_u8 reserved1;
+} MLAN_PACK_END UapRxPD, *PUapRxPD;
+
+/** Fixed size of station association event */
+#define ASSOC_EVENT_FIX_SIZE 12
+
+/** IEEEtypes_FrameCtl_t*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_FrameCtl_t
+{
+ /** Order */
+ t_u8 order:1;
+ /** Wep */
+ t_u8 wep:1;
+ /** More Data */
+ t_u8 more_data:1;
+ /** Power Mgmt */
+ t_u8 pwr_mgmt:1;
+ /** Retry */
+ t_u8 retry:1;
+ /** More Frag */
+ t_u8 more_frag:1;
+ /** From DS */
+ t_u8 from_ds:1;
+ /** To DS */
+ t_u8 to_ds:1;
+ /** Sub Type */
+ t_u8 sub_type:4;
+ /** Type */
+ t_u8 type:2;
+ /** Protocol Version */
+ t_u8 protocol_version:2;
+} MLAN_PACK_END IEEEtypes_FrameCtl_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_FrameCtl_t
+{
+ /** Protocol Version */
+ t_u8 protocol_version:2;
+ /** Type */
+ t_u8 type:2;
+ /** Sub Type */
+ t_u8 sub_type:4;
+ /** To DS */
+ t_u8 to_ds:1;
+ /** From DS */
+ t_u8 from_ds:1;
+ /** More Frag */
+ t_u8 more_frag:1;
+ /** Retry */
+ t_u8 retry:1;
+ /** Power Mgmt */
+ t_u8 pwr_mgmt:1;
+ /** More Data */
+ t_u8 more_data:1;
+ /** Wep */
+ t_u8 wep:1;
+ /** Order */
+ t_u8 order:1;
+} MLAN_PACK_END IEEEtypes_FrameCtl_t;
+#endif
+
+/** MrvlIETypes_MgmtFrameSet_t */
+typedef MLAN_PACK_START struct _MrvlIETypes_MgmtFrameSet_t
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** Frame Control */
+ IEEEtypes_FrameCtl_t frame_control;
+ /* t_u8 frame_contents[0]; */
+} MLAN_PACK_END MrvlIETypes_MgmtFrameSet_t;
+
+/** IEEEtypes_AssocRqst_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRqst_t
+{
+ /** Capability Info */
+ t_u16 cap_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /* t_u8 ie_buffer[0]; */
+} MLAN_PACK_END IEEEtypes_AssocRqst_t;
+
+/** IEEEtypes_ReAssocRqst_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ReAssocRqst_t
+{
+ /** Capability Info */
+ t_u16 cap_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Current AP Address */
+ t_u8 current_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /* t_u8 ie_buffer[0]; */
+} MLAN_PACK_END IEEEtypes_ReAssocRqst_t;
+#endif /* UAP_SUPPORT */
+
+/** wlan_802_11_header */
+typedef MLAN_PACK_START struct _wlan_802_11_header
+{
+ /** Frame Control */
+ t_u16 frm_ctl;
+ /** Duration ID */
+ t_u16 duration_id;
+ /** Address1 */
+ mlan_802_11_mac_addr addr1;
+ /** Address2 */
+ mlan_802_11_mac_addr addr2;
+ /** Address3 */
+ mlan_802_11_mac_addr addr3;
+ /** Sequence Control */
+ t_u16 seq_ctl;
+ /** Address4 */
+ mlan_802_11_mac_addr addr4;
+} MLAN_PACK_END wlan_802_11_header;
+
+/** wlan_802_11_header packet from FW with length */
+typedef MLAN_PACK_START struct _wlan_mgmt_pkt
+{
+ /** Packet Length */
+ t_u16 frm_len;
+ /** wlan_802_11_header */
+ wlan_802_11_header wlan_header;
+} MLAN_PACK_END wlan_mgmt_pkt;
+
+#ifdef STA_SUPPORT
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) */
+#define MAX_NO_OF_CHAN 40
+
+/** Channel-power table entries */
+typedef MLAN_PACK_START struct _chan_power_11d
+{
+ /** 11D channel */
+ t_u8 chan;
+ /** Band for channel */
+ t_u8 band;
+ /** 11D channel power */
+ t_u8 pwr;
+ /** AP seen on channel */
+ t_u8 ap_seen;
+} MLAN_PACK_END chan_power_11d_t;
+
+/** Region channel info */
+typedef MLAN_PACK_START struct _parsed_region_chan_11d
+{
+ /** 11D channel power per channel */
+ chan_power_11d_t chan_pwr[MAX_NO_OF_CHAN];
+ /** 11D number of channels */
+ t_u8 no_of_chan;
+} MLAN_PACK_END parsed_region_chan_11d_t;
+#endif /* STA_SUPPORT */
+
+/** ChanScanMode_t */
+typedef MLAN_PACK_START struct _ChanScanMode_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved_2_7:6;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt:1;
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan:1;
+#else
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan:1;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt:1;
+ /** Reserved */
+ t_u8 reserved_2_7:6;
+#endif
+} MLAN_PACK_END ChanScanMode_t;
+
+/** secondary channel is below */
+#define SECOND_CHANNEL_BELOW 0x30
+/** secondary channel is above */
+#define SECOND_CHANNEL_ABOVE 0x10
+/** channel offset */
+enum
+{
+ SEC_CHAN_NONE = 0,
+ SEC_CHAN_ABOVE = 1,
+ SEC_CHAN_BELOW = 3
+};
+/** channel bandwidth */
+enum
+{
+ CHAN_BW_20MHZ = 0,
+ CHAN_BW_10MHZ,
+ CHAN_BW_40MHZ,
+};
+/** ChanScanParamSet_t */
+typedef MLAN_PACK_START struct _ChanScanParamSet_t
+{
+ /** Channel scan parameter : Radio type */
+ t_u8 radio_type;
+ /** Channel scan parameter : Channel number */
+ t_u8 chan_number;
+ /** Channel scan parameter : Channel scan mode */
+ ChanScanMode_t chan_scan_mode;
+ /** Channel scan parameter : Minimum scan time */
+ t_u16 min_scan_time;
+ /** Channel scan parameter : Maximum scan time */
+ t_u16 max_scan_time;
+} MLAN_PACK_END ChanScanParamSet_t;
+
+/** MrvlIEtypes_ChanListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanListParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel scan parameters */
+ ChanScanParamSet_t chan_scan_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanListParamSet_t;
+
+/** ChanBandParamSet_t */
+typedef struct _ChanBandParamSet_t
+{
+ /** Channel scan parameter : Radio type */
+ t_u8 radio_type;
+ /** Channel number */
+ t_u8 chan_number;
+} ChanBandParamSet_t;
+
+/** MrvlIEtypes_ChanBandListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanBandListParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel Band parameters */
+ ChanBandParamSet_t chan_band_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanBandListParamSet_t;
+
+/** MrvlIEtypes_RatesParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RatesParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Rates */
+ t_u8 rates[1];
+} MLAN_PACK_END MrvlIEtypes_RatesParamSet_t;
+
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsIdParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_SsIdParamSet_t;
+
+/** MrvlIEtypes_NumProbes_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_NumProbes_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Number of probes */
+ t_u16 num_probes;
+} MLAN_PACK_END MrvlIEtypes_NumProbes_t;
+
+/** MrvlIEtypes_WildCardSsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WildCardSsIdParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Maximum SSID length */
+ t_u8 max_ssid_length;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_WildCardSsIdParamSet_t;
+
+/**TSF data size */
+#define TSF_DATA_SIZE 8
+/** Table of TSF values returned in the scan result */
+typedef MLAN_PACK_START struct _MrvlIEtypes_TsfTimestamp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** the length of each TSF data is 8 bytes, could be multiple TSF here */
+ t_u8 tsf_data[1];
+} MLAN_PACK_END MrvlIEtypes_TsfTimestamp_t;
+
+/** CfParamSet_t */
+typedef MLAN_PACK_START struct _CfParamSet_t
+{
+ /** CF parameter : Count */
+ t_u8 cfp_cnt;
+ /** CF parameter : Period */
+ t_u8 cfp_period;
+ /** CF parameter : Duration */
+ t_u16 cfp_max_duration;
+ /** CF parameter : Duration remaining */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END CfParamSet_t;
+
+/** IbssParamSet_t */
+typedef MLAN_PACK_START struct _IbssParamSet_t
+{
+ /** ATIM window value */
+ t_u16 atim_window;
+} MLAN_PACK_END IbssParamSet_t;
+
+/** MrvlIEtypes_SsParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** CF/IBSS parameters sets */
+ union
+ {
+ /** CF parameter set */
+ CfParamSet_t cf_param_set[1];
+ /** IBSS parameter set */
+ IbssParamSet_t ibss_param_set[1];
+ } cf_ibss;
+} MLAN_PACK_END MrvlIEtypes_SsParamSet_t;
+
+/** FhParamSet_t */
+typedef MLAN_PACK_START struct _FhParamSet_t
+{
+ /** FH parameter : Dwell time */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END FhParamSet_t;
+
+/** DsParamSet_t */
+typedef MLAN_PACK_START struct _DsParamSet_t
+{
+ /** Current channel number */
+ t_u8 current_chan;
+} MLAN_PACK_END DsParamSet_t;
+
+/** MrvlIEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PhyParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** FH/DS parameters */
+ union
+ {
+ /** FH parameter set */
+ FhParamSet_t fh_param_set[1];
+ /** DS parameter set */
+ DsParamSet_t ds_param_set[1];
+ } fh_ds;
+} MLAN_PACK_END MrvlIEtypes_PhyParamSet_t;
+
+/* Auth type to be used in the Authentication portion of an Assoc seq */
+/** MrvlIEtypes_AuthType_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_AuthType_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u16 auth_type;
+} MLAN_PACK_END MrvlIEtypes_AuthType_t;
+
+/** MrvlIETypes_ActionFrame_t */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t header; /**< Header */
+
+ t_u8 srcAddr[MLAN_MAC_ADDR_LENGTH];
+ t_u8 dstAddr[MLAN_MAC_ADDR_LENGTH];
+
+ IEEEtypes_ActionFrame_t actionFrame;
+
+} MLAN_PACK_END MrvlIETypes_ActionFrame_t;
+
+/** MrvlIEtypes_RxBaSync_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RxBaSync_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ /** tid */
+ t_u8 tid;
+ /** reserved field */
+ t_u8 reserved;
+ /** start seq num */
+ t_u16 seq_num;
+ /** bitmap len */
+ t_u16 bitmap_len;
+ /** bitmap */
+ t_u8 bitmap[1];
+} MLAN_PACK_END MrvlIEtypes_RxBaSync_t;
+
+/** MrvlIEtypes_RsnParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RsnParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSN IE */
+ t_u8 rsn_ie[1];
+} MLAN_PACK_END MrvlIEtypes_RsnParamSet_t;
+
+/** Key_param_set fixed length */
+#define KEYPARAMSET_FIXED_LEN 6
+
+/** MrvlIEtype_KeyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtype_KeyParamSet_t
+{
+ /** Type ID */
+ t_u16 type;
+ /** Length of Payload */
+ t_u16 length;
+ /** Type of Key: WEP=0, TKIP=1, AES=2 */
+ t_u16 key_type_id;
+ /** Key Control Info specific to a key_type_id */
+ t_u16 key_info;
+ /** Length of key */
+ t_u16 key_len;
+ /** Key material of size key_len */
+ t_u8 key[50];
+} MLAN_PACK_END MrvlIEtype_KeyParamSet_t;
+
+/** HostCmd_DS_802_11_KEY_MATERIAL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_KEY_MATERIAL
+{
+ /** Action */
+ t_u16 action;
+ /** Key parameter set */
+ MrvlIEtype_KeyParamSet_t key_param_set;
+} MLAN_PACK_END HostCmd_DS_802_11_KEY_MATERIAL;
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmQosInfo_t, *pWmmQosInfo_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _WmmEcw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmEcw_t, *pWmmEcw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmAciAifsn_t, *pWmmAciAifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _WmmAcParameters_t
+{
+ WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END WmmAcParameters_t, *pWmmAcParameters_t;
+
+/** Data structure of WMM parameter */
+typedef MLAN_PACK_START struct _WmmParameter_t
+{
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END WmmParameter_t, *pWmmParameter_t;
+
+/* Definition of firmware host command */
+/** HostCmd_DS_GEN */
+typedef MLAN_PACK_START struct _HostCmd_DS_GEN
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+} MLAN_PACK_END HostCmd_DS_GEN;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
+
+/** Address type: broadcast */
+#define ADDR_TYPE_BROADCAST 1
+/* Address type: unicast */
+#define ADDR_TYPE_UNICAST 2
+/* Address type: multicast */
+#define ADDR_TYPE_MULTICAST 3
+
+/** Ether type: any */
+#define ETHER_TYPE_ANY 0xffff
+/** Ether type: ARP */
+#define ETHER_TYPE_ARP 0x0608
+
+/** IPv4 address any */
+#define IPV4_ADDR_ANY 0xffffffff
+
+/** Header structure for ARP filter */
+typedef MLAN_PACK_START struct _arpfilter_header
+{
+ /** Type */
+ t_u16 type;
+ /** TLV length */
+ t_u16 len;
+} MLAN_PACK_END arpfilter_header;
+
+/** Filter entry structure */
+typedef MLAN_PACK_START struct _filter_entry
+{
+ /** Address type */
+ t_u16 addr_type;
+ /** Ether type */
+ t_u16 eth_type;
+ /** IPv4 address */
+ t_u32 ipv4_addr;
+} MLAN_PACK_END filter_entry;
+
+typedef MLAN_PACK_START struct _HostCmd_DS_MEF_CFG
+{
+ /** Criteria */
+ t_u32 criteria;
+ /** Number of entries */
+ t_u16 nentries;
+} MLAN_PACK_END HostCmd_DS_MEF_CFG;
+
+/* HostCmd_DS_802_11_SLEEP_PERIOD */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PERIOD
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+
+ /** Sleep Period in msec */
+ t_u16 sleep_pd;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PERIOD;
+
+/* HostCmd_DS_802_11_SLEEP_PARAMS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PARAMS
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** Sleep clock error in ppm */
+ t_u16 error;
+ /** Wakeup offset in usec */
+ t_u16 offset;
+ /** Clock stabilization time in usec */
+ t_u16 stable_time;
+ /** Control periodic calibration */
+ t_u8 cal_control;
+ /** Control the use of external sleep clock */
+ t_u8 external_sleep_clk;
+ /** Reserved field, should be set to zero */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PARAMS;
+
+/** Sleep response control */
+typedef enum _sleep_resp_ctrl
+{
+ RESP_NOT_NEEDED = 0,
+ RESP_NEEDED,
+} sleep_resp_ctrl;
+
+/** Structure definition for the new ieee power save parameters*/
+typedef struct __ps_param
+{
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+ /** Num dtims */
+ t_u16 multiple_dtims;
+ /** becaon miss interval */
+ t_u16 bcn_miss_timeout;
+ /** local listen interval */
+ t_u16 local_listen_interval;
+ /** Adhoc awake period */
+ t_u16 adhoc_wake_period;
+ /** mode - (0x01 - firmware to automatically choose PS_POLL or NULL mode, 0x02 - PS_POLL, 0x03 - NULL mode ) */
+ t_u16 mode;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+} ps_param;
+
+/** Structure definition for the new auto deep sleep command */
+typedef struct __auto_ds_param
+{
+ /** Deep sleep inactivity timeout */
+ t_u16 deep_sleep_timeout;
+} auto_ds_param;
+
+/** Structure definition for sleep confirmation in the new ps command */
+typedef struct __sleep_confirm_param
+{
+ /** response control 0x00 - response not needed, 0x01 - response needed */
+ t_u16 resp_ctrl;
+} sleep_confirm_param;
+
+/** bitmap for get auto deepsleep */
+#define BITMAP_AUTO_DS 0x01
+/** bitmap for sta power save */
+#define BITMAP_STA_PS 0x10
+/** bitmap for uap inactivity based PS */
+#define BITMAP_UAP_INACT_PS 0x100
+/** bitmap for uap DTIM PS */
+#define BITMAP_UAP_DTIM_PS 0x200
+/** Structure definition for the new ieee power save parameters*/
+typedef struct _auto_ps_param
+{
+ /** bitmap for enable power save mode */
+ t_u16 ps_bitmap;
+ /* auto deep sleep parameter, sta power save parameter uap inactivity
+ parameter uap DTIM parameter */
+} auto_ps_param;
+
+/** fix size for auto ps */
+#define AUTO_PS_FIX_SIZE 4
+
+/** TLV type : auto ds param */
+#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 0x71) // 0x0171
+/** TLV type : ps param */
+#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 0x72) // 0x0172
+
+/** MrvlIEtypes_auto_ds_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_auto_ds_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** auto ds param */
+ auto_ds_param param;
+} MLAN_PACK_END MrvlIEtypes_auto_ds_param_t;
+
+/** MrvlIEtypes_ps_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ps_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** ps param */
+ ps_param param;
+} MLAN_PACK_END MrvlIEtypes_ps_param_t;
+
+/** Structure definition for new power save command */
+typedef MLAN_PACK_START struct _HostCmd_DS_PS_MODE_ENH
+{
+ /** Action */
+ t_u16 action;
+ /** Data speciifc to action */
+ /* For IEEE power save data will be as UINT16 mode (0x01 - firmware to
+ automatically choose PS_POLL or NULL mode, 0x02 - PS_POLL, 0x03 - NULL
+ mode ) UINT16 NullpacketInterval UINT16 NumDtims UINT16
+ BeaconMissInterval UINT16 locallisteninterval UINT16 adhocawakeperiod */
+
+ /* For auto deep sleep */
+ /* UINT16 Deep sleep inactivity timeout */
+
+ /* For PS sleep confirm UINT16 responeCtrl - 0x00 - reponse from fw not
+ needed, 0x01 - response from fw is needed */
+
+ union
+ {
+ /** PS param definition */
+ ps_param opt_ps;
+ /** Auto ds param definition */
+ auto_ds_param auto_ds;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+ /** bitmap for get PS info and Disable PS mode */
+ t_u16 ps_bitmap;
+ /** auto ps param */
+ auto_ps_param auto_ps;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_PS_MODE_ENH;
+
+/** HostCmd_DS_GET_HW_SPEC */
+typedef MLAN_PACK_START struct _HostCmd_DS_GET_HW_SPEC
+{
+ /** HW Interface version number */
+ t_u16 hw_if_version;
+ /** HW version number */
+ t_u16 version;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Max no of Multicast address */
+ t_u16 num_of_mcast_adr;
+ /** MAC address */
+ t_u8 permanent_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Region Code */
+ t_u16 region_code;
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+ /** FW release number, example 0x1234=1.2.3.4 */
+ t_u32 fw_release_number;
+ /** Reserved field */
+ t_u32 reserved_1;
+ /** Reserved field */
+ t_u32 reserved_2;
+ /** Reserved field */
+ t_u32 reserved_3;
+ /** FW/HW Capability */
+ t_u32 fw_cap_info;
+ /** 802.11n Device Capabilities */
+ t_u32 dot_11n_dev_cap;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 dev_mcs_support;
+ /** Valid end port at init */
+ t_u16 mp_end_port;
+ /** mgmt IE buffer count */
+ t_u16 mgmt_buf_count;
+} MLAN_PACK_END HostCmd_DS_GET_HW_SPEC;
+
+/** HostCmd_DS_802_11_CFG_DATA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_CFG_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+} MLAN_PACK_END HostCmd_DS_802_11_CFG_DATA;
+
+/** HostCmd_DS_CMD_802_11_RSSI_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO
+{
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for Beacon */
+ t_u16 nbcn;
+ /** Reserved field 0 */
+ t_u16 reserved[9];
+ /** Reserved field 1 */
+ t_u64 reserved_1;
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO;
+
+/** HostCmd_DS_802_11_RSSI_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO_RSP
+{
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for beacon */
+ t_u16 nbcn;
+ /** Last Data RSSI in dBm */
+ t_s16 data_rssi_last;
+ /** Last Data NF in dBm */
+ t_s16 data_nf_last;
+ /** AVG DATA RSSI in dBm */
+ t_s16 data_rssi_avg;
+ /** AVG DATA NF in dBm */
+ t_s16 data_nf_avg;
+ /** Last BEACON RSSI in dBm */
+ t_s16 bcn_rssi_last;
+ /** Last BEACON NF in dBm */
+ t_s16 bcn_nf_last;
+ /** AVG BEACON RSSI in dBm */
+ t_s16 bcn_rssi_avg;
+ /** AVG BEACON NF in dBm */
+ t_s16 bcn_nf_avg;
+ /** Last RSSI Beacon TSF */
+ t_u64 tsf_bcn;
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO_RSP;
+
+/** HostCmd_DS_802_11_MAC_ADDRESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_MAC_ADDRESS
+{
+ /** Action */
+ t_u16 action;
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END HostCmd_DS_802_11_MAC_ADDRESS;
+
+/** HostCmd_DS_MAC_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_CONTROL
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_MAC_CONTROL;
+
+/** HostCmd_DS_CMD_TX_DATA_PAUSE */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_TX_DATA_PAUSE
+{
+ /** Action */
+ t_u16 action;
+ /** Enable/disable Tx data pause */
+ t_u8 enable_tx_pause;
+ /** Max number of TX buffers allowed for all PS clients*/
+ t_u8 pause_tx_count;
+} MLAN_PACK_END HostCmd_DS_CMD_TX_DATA_PAUSE;
+
+/** TLV type : TX pause TLV */
+#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 0x94) // 0x0194
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_pause_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** peer mac address */
+ t_u8 peermac[MLAN_MAC_ADDR_LENGTH];
+ /** Tx pause state, 1--pause, 0--free flowing */
+ t_u8 tx_pause;
+ /** total packets queued for the client */
+ t_u8 pkt_cnt;
+} MLAN_PACK_END MrvlIEtypes_tx_pause_t;
+
+/** HostCmd_CMD_MAC_MULTICAST_ADR */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_MULTICAST_ADR
+{
+ /** Action */
+ t_u16 action;
+ /** Number of addresses */
+ t_u16 num_of_adrs;
+ /** List of MAC */
+ t_u8 mac_list[MLAN_MAC_ADDR_LENGTH * MLAN_MAX_MULTICAST_LIST_SIZE];
+} MLAN_PACK_END HostCmd_DS_MAC_MULTICAST_ADR;
+
+/** HostCmd_CMD_802_11_DEAUTHENTICATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_DEAUTHENTICATE
+{
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Deauthentication resaon code */
+ t_u16 reason_code;
+} MLAN_PACK_END HostCmd_DS_802_11_DEAUTHENTICATE;
+
+/** HostCmd_DS_802_11_ASSOCIATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE
+{
+ /** Peer STA address */
+ t_u8 peer_sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+
+ /**
+ * MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_PhyParamSet_t PhyParamSet;
+ * MrvlIEtypes_SsParamSet_t SsParamSet;
+ * MrvlIEtypes_RatesParamSet_t RatesParamSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE;
+
+/** HostCmd_CMD_802_11_ASSOCIATE response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE_RSP
+{
+ /** Association response structure */
+ IEEEtypes_AssocRsp_t assoc_rsp;
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE_RSP;
+
+/** HostCmd_DS_802_11_AD_HOC_START*/
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START
+{
+ /** AdHoc SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START_RESULT
+{
+ /** Padding */
+ t_u8 pad[3];
+ /** AdHoc BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Padding to sync with FW structure*/
+ t_u8 pad2[2];
+ /** Result */
+ t_u8 result;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START_RESULT;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN_RESULT
+{
+ /** Result */
+ t_u8 result;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN_RESULT;
+
+/** AdHoc_BssDesc_t */
+typedef MLAN_PACK_START struct _AdHoc_BssDesc_t
+{
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Local time */
+ t_u8 local_time[8];
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 data_rates[HOSTCMD_SUPPORTED_RATES];
+
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
+ * It is used in the Adhoc join command and will cause a
+ * binary layout mismatch with the firmware
+ */
+} MLAN_PACK_END AdHoc_BssDesc_t;
+
+/** HostCmd_DS_802_11_AD_HOC_JOIN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN
+{
+ /** AdHoc BSS descriptor */
+ AdHoc_BssDesc_t bss_descriptor;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Reserved field */
+ t_u16 reserved2;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN;
+
+/** Interrupt Raising Edge */
+#define INT_RASING_EDGE 0
+/** Interrupt Falling Edge */
+#define INT_FALLING_EDGE 1
+
+/** Delay 1 usec */
+#define DELAY_1_US 1
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_GPIO_INT_CONFIG
+{
+ /** Action */
+ t_u16 action;
+ /** GPIO interrupt pin */
+ t_u16 gpio_pin;
+ /** GPIO interrupt edge, 1: failing edge; 0: raising edge */
+ t_u16 gpio_int_edge;
+ /** GPIO interrupt pulse widthin usec units */
+ t_u16 gpio_pulse_width;
+} MLAN_PACK_END HostCmd_DS_SDIO_GPIO_INT_CONFIG;
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_PULL_CTRL
+{
+ /** Action */
+ t_u16 action;
+ /** The delay of pulling up in us */
+ t_u16 pull_up;
+ /** The delay of pulling down in us */
+ t_u16 pull_down;
+} MLAN_PACK_END HostCmd_DS_SDIO_PULL_CTRL;
+
+/** HostCmd_DS_802_11_GET_LOG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_GET_LOG
+{
+ /** Number of multicast transmitted frames */
+ t_u32 mcast_tx_frame;
+ /** Number of failures */
+ t_u32 failed;
+ /** Number of retries */
+ t_u32 retry;
+ /** Number of multiretries */
+ t_u32 multiretry;
+ /** Number of duplicate frames */
+ t_u32 frame_dup;
+ /** Number of RTS success */
+ t_u32 rts_success;
+ /** Number of RTS failure */
+ t_u32 rts_failure;
+ /** Number of acknowledgement failure */
+ t_u32 ack_failure;
+ /** Number of fragmented packets received */
+ t_u32 rx_frag;
+ /** Number of multicast frames received */
+ t_u32 mcast_rx_frame;
+ /** FCS error */
+ t_u32 fcs_error;
+ /** Number of transmitted frames */
+ t_u32 tx_frame;
+ /** Reserved field */
+ t_u32 reserved;
+ /** Number of WEP icv error for each key */
+ t_u32 wep_icv_err_cnt[4];
+} MLAN_PACK_END HostCmd_DS_802_11_GET_LOG;
+
+/**_HostCmd_TX_RATE_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_TX_RATE_QUERY
+{
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ t_u8 ht_info;
+} MLAN_PACK_END HostCmd_TX_RATE_QUERY;
+
+typedef MLAN_PACK_START struct _hs_config_param
+{
+ /** bit0=1: broadcast data
+ * bit1=1: unicast data
+ * bit2=1: mac events
+ * bit3=1: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u8 gpio;
+ /** gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */
+ t_u8 gap;
+} MLAN_PACK_END hs_config_param;
+
+/** HS Action 0x0001 - Configure enhanced host sleep mode, 0x0002 - Activate enhanced host sleep mode */
+typedef enum _Host_Sleep_Action
+{
+ HS_CONFIGURE = 0x0001,
+ HS_ACTIVATE = 0x0002,
+} Host_Sleep_Action;
+
+/** Structure definition for activating enhanced hs */
+typedef MLAN_PACK_START struct __hs_activate_param
+{
+ /** response control 0x00 - response not needed, 0x01 - response needed */
+ t_u16 resp_ctrl;
+} MLAN_PACK_END hs_activate_param;
+
+/** HostCmd_DS_802_11_HS_CFG_ENH */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_HS_CFG_ENH
+{
+ /** Action 0x0001 - Configure enhanced host sleep mode, 0x0002 - Activate enhanced host sleep mode */
+ t_u16 action;
+
+ union
+ {
+ /** Configure enhanced hs */
+ hs_config_param hs_config;
+ /** Activate enhanced hs */
+ hs_activate_param hs_activate;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_HS_CFG_ENH;
+
+/** SNMP_MIB_INDEX */
+typedef enum _SNMP_MIB_INDEX
+{
+ OpRateSet_i = 1,
+ DtimPeriod_i = 3,
+ RtsThresh_i = 5,
+ ShortRetryLim_i = 6,
+ LongRetryLim_i = 7,
+ FragThresh_i = 8,
+ Dot11D_i = 9,
+ Dot11H_i = 10,
+ WwsMode_i = 17,
+ Thermal_i = 34,
+} SNMP_MIB_INDEX;
+
+/** max SNMP buf size */
+#define MAX_SNMP_BUF_SIZE 128
+
+/** HostCmd_CMD_802_11_SNMP_MIB */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SNMP_MIB
+{
+ /** SNMP query type */
+ t_u16 query_type;
+ /** SNMP object ID */
+ t_u16 oid;
+ /** SNMP buffer size */
+ t_u16 buf_size;
+ /** Value */
+ t_u8 value[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SNMP_MIB;
+
+/** Radio on */
+#define RADIO_ON 0x01
+/** Radio off */
+#define RADIO_OFF 0x00
+
+/** HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RADIO_CONTROL
+{
+ /** Action */
+ t_u16 action;
+ /** Control */
+ t_u16 control;
+} MLAN_PACK_END HostCmd_DS_802_11_RADIO_CONTROL;
+
+/** MrvlRateScope_t */
+typedef MLAN_PACK_START struct _MrvlRateScope_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Bitmap of HR/DSSS rates */
+ t_u16 hr_dsss_rate_bitmap;
+ /** Bitmap of OFDM rates */
+ t_u16 ofdm_rate_bitmap;
+ /** Bitmap of HT-MCSs allowed for initial rate */
+ t_u16 ht_mcs_rate_bitmap[8];
+} MLAN_PACK_END MrvlRateScope_t;
+
+/** MrvlRateDropControl_t */
+typedef MLAN_PACK_START struct _MrvlRateDropControl_t
+{
+ /** Header Length */
+ t_u16 length;
+ /** Rate Information */
+ t_u32 rate_info[1];
+} MLAN_PACK_END MrvlRateDropControl_t;
+
+/** MrvlRateDropPattern_t */
+typedef MLAN_PACK_START struct _MrvlRateDropPattern_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Rate Drop Mode */
+ t_u32 rate_drop_mode;
+ /* MrvlRateDropControl_t RateDropControl[0]; */
+} MLAN_PACK_END MrvlRateDropPattern_t;
+
+/** HostCmd_DS_TX_RATE_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_RATE_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Tx Rate Configuration Index */
+ t_u16 cfg_index;
+ /* MrvlRateScope_t RateScope; MrvlRateDropPattern_t RateDrop; */
+} MLAN_PACK_END HostCmd_DS_TX_RATE_CFG;
+
+/** Power_Group_t */
+typedef MLAN_PACK_START struct _Power_Group_t
+{
+ /** Modulation Class */
+ t_u8 modulation_class;
+ /** MCS Code or Legacy RateID */
+ t_u8 first_rate_code;
+ /** MCS Code or Legacy RateID */
+ t_u8 last_rate_code;
+ /** Power Adjustment Step */
+ t_s8 power_step;
+ /** Minimal Tx Power Level [dBm] */
+ t_s8 power_min;
+ /** Maximal Tx Power Level [dBm] */
+ t_s8 power_max;
+ /** 0: HTBW20, 1: HTBW40 */
+ t_u8 ht_bandwidth;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END Power_Group_t;
+
+/** MrvlTypes_Power_Group_t */
+typedef MLAN_PACK_START struct _MrvlTypes_Power_Group_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /* Power_Group_t PowerGroups */
+} MLAN_PACK_END MrvlTypes_Power_Group_t;
+
+/** HostCmd_CMD_TXPWR_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TXPWR_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Power group configuration index */
+ t_u16 cfg_index;
+ /** Power group configuration mode */
+ t_u32 mode;
+ /* MrvlTypes_Power_Group_t PowerGrpCfg[0] */
+} MLAN_PACK_END HostCmd_DS_TXPWR_CFG;
+
+/** HostCmd_CMD_802_11_RF_TX_POWER */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_TX_POWER
+{
+ /** Action */
+ t_u16 action;
+ /** Current power level */
+ t_u16 current_level;
+ /** Maximum power */
+ t_u8 max_power;
+ /** Minimum power */
+ t_u8 min_power;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_TX_POWER;
+
+/** Connection type infra */
+#define CONNECTION_TYPE_INFRA 0
+/** Connection type adhoc */
+#define CONNECTION_TYPE_ADHOC 1
+#ifdef WIFI_DIRECT_SUPPORT
+/** BSS Mode: WIFIDIRECT Client */
+#define BSS_MODE_WIFIDIRECT_CLIENT 0
+/** BSS Mode: WIFIDIRECT GO */
+#define BSS_MODE_WIFIDIRECT_GO 2
+#endif
+/** HostCmd_DS_SET_BSS_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_SET_BSS_MODE
+{
+ /** connection type */
+ t_u8 con_type;
+} MLAN_PACK_END HostCmd_DS_SET_BSS_MODE;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** HostCmd_DS_REMAIN_ON_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_REMAIN_ON_CHANNEL
+{
+ /** Action 0-GET, 1-SET, 4 CLEAR*/
+ t_u16 action;
+ /** Not used set to zero */
+ t_u8 status;
+ /** Not used set to zero */
+ t_u8 reserved;
+ /** Band cfg */
+ t_u8 bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} MLAN_PACK_END HostCmd_DS_REMAIN_ON_CHANNEL;
+
+/** HostCmd_DS_WIFI_DIRECT_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_WIFI_DIRECT_MODE
+{
+ /** Action 0-GET, 1-SET*/
+ t_u16 action;
+ /**0:disable 1:listen 2:GO 3:p2p client 4:find 5:stop find*/
+ t_u16 mode;
+} MLAN_PACK_END HostCmd_DS_WIFI_DIRECT_MODE;
+#endif
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command process module to configure the firmware
+ * scan command prepared by wlan_cmd_802_11_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+typedef MLAN_PACK_START struct _wlan_scan_cmd_config
+{
+ /**
+ * BSS Type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+
+ /**
+ * Specific BSSID used to filter scan results in the firmware
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+
+ /**
+ * Length of TLVs sent in command starting at tlvBuffer
+ */
+ t_u32 tlv_buf_len;
+
+ /**
+ * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
+ * TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
+ */
+ t_u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
+ here */
+} MLAN_PACK_END wlan_scan_cmd_config;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} MLAN_PACK_END wlan_get_scan_table_info;
+
+/** Generic structure defined for parsing WPA/RSN IEs for GTK/PTK OUIs */
+typedef MLAN_PACK_START struct
+{
+ /** Group key oui */
+ t_u8 GrpKeyOui[4];
+ /** Number of PTKs */
+ t_u8 PtkCnt[2];
+ /** Ptk body starts here */
+ t_u8 PtkBody[4];
+} MLAN_PACK_END IEBody;
+#endif /* STA_SUPPORT */
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN
+ */
+/** HostCmd_DS_802_11_SCAN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN
+{
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN;
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN_EXT
+ */
+/** HostCmd_DS_802_11_SCAN_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_EXT
+{
+ /** Reserved */
+ t_u32 reserved;
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_Bssid_List_t BssIdList;
+ * MrvlIEtypes_SsIdParamSet_t SSIDParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ * MrvlIEtypes_NumProbes_t NumProbes;
+ * MrvlIEtypes_WildCardSsIdParamSet_t WildCardSSIDParamSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_EXT;
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bss_Scan_Rsp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSSID of the BSS descriptor */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon/Probe response buffer */
+ t_u8 frame_body[1];
+} MLAN_PACK_END MrvlIEtypes_Bss_Scan_Rsp_t;
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bss_Scan_Info_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSSI for scan entry */
+ t_s16 rssi;
+ /** Channel ANPI */
+ t_s16 anpi;
+ /** Channel load (parts per 255) */
+ t_u8 cca_busy_fraction;
+ /** Band */
+ t_u8 band;
+ /** Channel */
+ t_u8 channel;
+ /** Reserved */
+ t_u8 reserved;
+ /** TSF data */
+ t_u64 tsf;
+} MLAN_PACK_END MrvlIEtypes_Bss_Scan_Info_t;
+
+/** HostCmd_DS_RX_MGMT_IND */
+typedef MLAN_PACK_START struct _HostCmd_DS_RX_MGMT_IND
+{
+ /** Action */
+ t_u16 action;
+ /** Mgmt frame subtype mask */
+ t_u32 mgmt_subtype_mask;
+} MLAN_PACK_END HostCmd_DS_RX_MGMT_IND;
+
+/** HostCmd_DS_802_11_SCAN_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_RSP
+{
+ /** Size of BSS descriptor */
+ t_u16 bss_descript_size;
+ /** Numner of sets */
+ t_u8 number_of_sets;
+ /** BSS descriptor and TLV buffer */
+ t_u8 bss_desc_and_tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_RSP;
+
+/** HostCmd_DS_802_11_BG_SCAN_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_CONFIG
+{
+ /** action */
+ t_u16 action;
+ /** 0: disable, 1: enable */
+ t_u8 enable;
+ /** bss type */
+ t_u8 bss_type;
+ /** num of channel per scan */
+ t_u8 chan_per_scan;
+ /** reserved field */
+ t_u8 reserved;
+ /** reserved field */
+ t_u16 reserved1;
+ /** interval between consecutive scans */
+ t_u32 scan_interval;
+ /** reserved field */
+ t_u32 reserved2;
+ /** condition to trigger report to host */
+ t_u32 report_condition;
+ /** reserved field */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_CONFIG;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY
+{
+ /** Flush */
+ t_u8 flush;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
+{
+ /** Report condition */
+ t_u32 report_condition;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+
+/** MrvlIEtypes_StartLater_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_StartLater_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* 0 - BGScan start immediately, 1 - BGScan will start later after "Scan
+ Interval" */
+ t_u16 value;
+} MLAN_PACK_END MrvlIEtypes_StartLater_t;
+
+/** MrvlIEtypes_RepeatCount_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RepeatCount_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* Repeat count */
+ t_u16 repeat_count;
+} MLAN_PACK_END MrvlIEtypes_RepeatCount_t;
+
+/** MrvlIEtypes_DomainParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_DomainParamSet
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END MrvlIEtypes_DomainParamSet_t;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO
+{
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+{
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
+
+/** HostCmd_DS_11N_ADDBA_REQ */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_REQ
+{
+ /** Result of the ADDBA Request Operation */
+ t_u8 add_req_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_REQ;
+
+/** HostCmd_DS_11N_ADDBA_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_RSP
+{
+ /** Result of the ADDBA Response Operation */
+ t_u8 add_rsp_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Status Code */
+ t_u16 status_code;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_RSP;
+
+/** HostCmd_DS_11N_DELBA */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_DELBA
+{
+ /** Result of the ADDBA Request Operation */
+ t_u8 del_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u16 del_ba_param_set;
+ /** Reason Code sent for DELBA */
+ t_u16 reason_code;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END HostCmd_DS_11N_DELBA;
+
+/** HostCmd_DS_11N_BATIMEOUT */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_BATIMEOUT
+{
+ /** TID */
+ t_u8 tid;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u8 origninator;
+} MLAN_PACK_END HostCmd_DS_11N_BATIMEOUT;
+
+/** HostCmd_DS_11N_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** HTTxCap */
+ t_u16 ht_tx_cap;
+ /** HTTxInfo */
+ t_u16 ht_tx_info;
+ /** Misc configuration */
+ t_u16 misc_config;
+} MLAN_PACK_END HostCmd_DS_11N_CFG;
+
+/** HostCmd_DS_TXBUF_CFG*/
+typedef MLAN_PACK_START struct _HostCmd_DS_TXBUF_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Buffer Size */
+ t_u16 buff_size;
+ /** End Port_for Multiport */
+ t_u16 mp_end_port;
+ /** Reserved */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_TXBUF_CFG;
+
+/** HostCmd_DS_AMSDU_AGGR_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_AMSDU_AGGR_CTRL
+{
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** Get the current Buffer Size valid */
+ t_u16 curr_buf_size;
+} MLAN_PACK_END HostCmd_DS_AMSDU_AGGR_CTRL;
+
+/** HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG
+{
+ /** Action */
+ t_u16 action;
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Length of clocks */
+ t_u16 sys_clk_len;
+ /** System clocks */
+ t_u16 sys_clk[16];
+} MLAN_PACK_END HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG;
+
+/** MrvlIEtypes_WmmParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WmmParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM IE */
+ t_u8 wmm_ie[1];
+} MLAN_PACK_END MrvlIEtypes_WmmParamSet_t;
+
+/** MrvlIEtypes_WmmQueueStatus_t */
+typedef MLAN_PACK_START struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Queue index */
+ t_u8 queue_index;
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Medium time allocation in 32us units*/
+ t_u16 medium_time;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Reserved */
+ t_u32 reserved;
+} MLAN_PACK_END MrvlIEtypes_WmmQueueStatus_t;
+
+/** Size of a TSPEC. Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE 63
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES 256
+
+/** Extra TLV bytes allocated in messages for configuring WMM Queues */
+#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS 7
+
+/**
+ * @brief Firmware command structure to retrieve the firmware WMM status.
+ *
+ * Used to retrieve the status of each WMM AC Queue in TLV
+ * format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
+ * parameter IE advertised by the AP.
+ *
+ * Used in response to a EVENT_WMM_STATUS_CHANGE event signaling
+ * a QOS change on one of the ACs or a change in the WMM Parameter in
+ * the Beacon.
+ *
+ * TLV based command, byte arrays used for max sizing purpose. There are no
+ * arguments sent in the command, the TLVs are returned by the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ /** Queue status TLV */
+ t_u8 queue_status_tlv[sizeof(MrvlIEtypes_WmmQueueStatus_t)
+ * MAX_AC_QUEUES];
+ /** WMM parameter TLV */
+ t_u8 wmm_param_tlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
+}
+MLAN_PACK_END HostCmd_DS_WMM_GET_STATUS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_status_code; /**< IEEE status code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+ t_u8 addts_extra_ie_buf[WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buffer */
+} MLAN_PACK_END HostCmd_DS_WMM_ADDTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_reason_code; /**< IEEE reason code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+} MLAN_PACK_END HostCmd_DS_WMM_DELTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
+ *
+ * Set/Get/Default the Queue parameters for a specific AC in the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ /** @brief MSDU lifetime expiry per 802.11e
+ *
+ * - Ignored if 0 on a set command
+ * - Set to the 802.11e specified 500 TUs when defaulted
+ */
+ t_u16 msdu_lifetime_expiry;
+ t_u8 tlv_buffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES]; /**< Not supported */
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_CONFIG;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
+ *
+ * Turn statistical collection on/off for a given AC or retrieve the
+ * accumulated stats for an AC and clear them in the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_wmm_queue_stats_action_e action; /**< Start, Stop, or Get */
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 select_bin:7; /**< WMM_AC_BK(0) to WMM_AC_VO(3), or TID */
+ t_u8 select_is_userpri:1; /**< Set if select_bin is UP, Clear for AC */
+#else
+ t_u8 select_is_userpri:1; /**< Set if select_bin is UP, Clear for AC */
+ t_u8 select_bin:7; /**< WMM_AC_BK(0) to WMM_AC_VO(3), or TID */
+#endif
+ t_u16 pkt_count; /**< Number of successful packets transmitted */
+ t_u16 pkt_loss; /**< Packets lost; not included in pktCount */
+ t_u32 avg_queue_delay; /**< Average Queue delay in microsec */
+ t_u32 avg_tx_delay; /**< Average Transmission delay in microsec */
+ t_u16 used_time; /**< Calc used time - units of 32 microsec */
+ t_u16 policed_time; /**< Calc policed time - units of 32 microsec */
+ /** @brief Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[WMM_STATS_PKTS_HIST_BINS];
+ /** Reserved */
+ t_u16 reserved_1;
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_STATS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_TS_STATUS firmware cmd
+ *
+ * Query the firmware to get the status of the WMM Traffic Streams
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Uplink(1), Downlink(2), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END HostCmd_DS_WMM_TS_STATUS;
+
+/** Firmware status for a specific AC */
+typedef MLAN_PACK_START struct
+{
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+} MLAN_PACK_END WmmAcStatus_t;
+
+/** Local Power Capability */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PowerCapability_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Minmum power */
+ t_s8 min_power;
+ /** Maximum power */
+ t_s8 max_power;
+} MLAN_PACK_END MrvlIEtypes_PowerCapability_t;
+
+/** HT Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTCap_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END MrvlIETypes_HTCap_t;
+
+/** HT Information element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTInfo_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END MrvlIETypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence element */
+typedef MLAN_PACK_START struct _MrvlIETypes_2040BSSCo_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END MrvlIETypes_2040BSSCo_t;
+
+/** Extended Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_ExtCap_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END MrvlIETypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters element */
+typedef MLAN_PACK_START struct _MrvlIETypes_OverlapBSSScanParam_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END MrvlIETypes_OverlapBSSScanParam_t;
+
+/** Set of MCS values that STA desires to use within the BSS */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTOperationalMCSSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** Bitmap indicating MCSs that STA desires to use within the BSS */
+ t_u8 ht_operational_mcs_bitmap[16];
+} MLAN_PACK_END MrvlIETypes_HTOperationalMCSSet_t;
+
+/** bf global args */
+typedef struct MLAN_PACK_START _bf_global_cfg_args
+{
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END bf_global_cfg_args;
+
+/** bf_trigger_sound_args_t */
+typedef MLAN_PACK_START struct _bf_trigger_sound_args_t
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} MLAN_PACK_END bf_trigger_sound_args_t;
+
+/** bf periodicity args */
+typedef MLAN_PACK_START struct _bf_periodicity_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} MLAN_PACK_END bf_periodicity_args;
+
+/** bf peer configuration args */
+typedef struct MLAN_PACK_START _bf_peer_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} MLAN_PACK_END bf_peer_args;
+
+/** bf_snr_thr_t */
+typedef MLAN_PACK_START struct _bf_snr_thr_t
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR */
+ t_u8 snr;
+} MLAN_PACK_END bf_snr_thr_t;
+
+/** HostCmd_DS_TX_BF_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_BF_CFG
+{
+ /* Beamforming action */
+ t_u16 bf_action;
+ /* action - SET/GET */
+ t_u16 action;
+
+ MLAN_PACK_START union
+ {
+ bf_global_cfg_args bf_global_cfg;
+ bf_trigger_sound_args_t bf_sound_args;
+ bf_periodicity_args bf_periodicity;
+ bf_peer_args tx_bf_peer;
+ bf_snr_thr_t bf_snr;
+ } MLAN_PACK_END body;
+} MLAN_PACK_END HostCmd_DS_TX_BF_CFG;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** MrvlIEtypes_psk_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_psk_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PSK */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_psk_t;
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** MrvlIEtypes_PMK_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PMK_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PMK */
+ t_u8 pmk[1];
+} MLAN_PACK_END MrvlIEtypes_PMK_t;
+
+/** MrvlIEtypes_Passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Passphrase_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Passphrase */
+ char passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_Passphrase_t;
+
+/* unicastCipher -
+ * Bit 0 : RFU
+ * Bit 1 : RFU
+ * Bit 2 : TKIP
+ * Bit 3 : AES CCKM
+ * Bit 2-7 : RFU
+ * multicastCipher -
+ * Bit 0 : WEP40
+ * Bit 1 : WEP104
+ * Bit 2 : TKIP
+ * Bit 3 : AES
+ * Bit 4-7 : Reserved for now
+ */
+/** MrvlIEtypes_Cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PairCipher */
+ t_u8 pair_cipher;
+ /** GroupCipher */
+ t_u8 group_cipher;
+} MLAN_PACK_END MrvlIEtypes_Cipher_t;
+
+/* rsnMode -
+ * Bit 0 : No RSN
+ * Bit 1-2 : RFU
+ * Bit 3 : WPA
+ * Bit 4 : WPA-NONE
+ * Bit 5 : WPA2
+ * Bit 6 : AES CCKM
+ * Bit 7-15 : RFU
+ */
+/** MrvlIEtypes_EncrProto_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_EncrProto_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** EncrProto */
+ t_u16 rsn_mode;
+} MLAN_PACK_END MrvlIEtypes_EncrProto_t;
+
+/** MrvlIEtypes_Bssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bssid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Bssid */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_Bssid_t;
+
+/*
+ * This struct will handle GET,SET,CLEAR function for embedded
+ * supplicant.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PMK
+ */
+/** HostCmd_DS_802_11_SUPPLICANT_PMK */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PMK
+{
+ /** CMD Action GET/SET/CLEAR */
+ t_u16 action;
+ /** CacheResult initialized to 0 */
+ t_u16 cache_result;
+ /** TLV Buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsidParamSet_t SsidParamSet;
+ * MrvlIEtypes_PMK_t Pmk;
+ * MrvlIEtypes_Passphrase_t Passphrase;
+ * MrvlIEtypes_Bssid_t Bssid;
+ **/
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PMK;
+
+/*
+ * This struct will GET the Supplicant supported bitmaps
+ * The GET_CURRENT action will get the network profile used
+ * for the current assocation.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PROFILE
+ */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PROFILE
+{
+ /** GET/SET/GET_CURRENT */
+ t_u16 action;
+ /** Reserved */
+ t_u16 reserved;
+ /** TLVBuffer */
+ t_u8 tlv_buf[1];
+ /* MrvlIEtypes_EncrProto_t */
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PROFILE;
+
+/** HostCmd_CMD_802_11_RF_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_CHANNEL
+{
+ /** Action */
+ t_u16 action;
+ /** Current channel */
+ t_u16 current_channel;
+ /** RF type */
+ t_u16 rf_type;
+ /** Reserved field */
+ t_u16 reserved;
+#ifdef STA_SUPPORT
+ /** Reserved */
+ t_u8 reserved_1[32];
+#else /* STA_SUPPORT */
+ /** List of channels */
+ t_u8 channel_list[32];
+#endif /* !STA_SUPPORT */
+} MLAN_PACK_END HostCmd_DS_802_11_RF_CHANNEL;
+
+/** HostCmd_DS_VERSION_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_VERSION_EXT
+{
+ /** Selected version string */
+ t_u8 version_str_sel;
+ /** Version string */
+ char version_str[128];
+} MLAN_PACK_END HostCmd_DS_VERSION_EXT;
+
+/** HostCmd_CMD_802_11_RF_ANTENNA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_ANTENNA
+{
+ /** Action for Tx antenna */
+ t_u16 action_tx;
+ /** Tx antenna mode Bit0:1, Bit1:2, Bit0-1:1+2, 0xffff: diversity */
+ t_u16 tx_antenna_mode;
+ /** Action for Rx antenna */
+ t_u16 action_rx;
+ /** Rx antenna mode Bit0:1, Bit1:2, Bit0-1:1+2, 0xffff: diversity */
+ t_u16 rx_antenna_mode;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_ANTENNA;
+
+/** HostCmd_DS_802_11_IBSS_STATUS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_IBSS_STATUS
+{
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** ATIM window interval */
+ t_u16 atim_window;
+ /** User G rate protection */
+ t_u16 use_g_rate_protect;
+} MLAN_PACK_END HostCmd_DS_802_11_IBSS_STATUS;
+
+/** HostCmd_DS_MGMT_IE_LIST_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_MGMT_IE_LIST
+{
+ /** Action */
+ t_u16 action;
+ /** Get/Set mgmt IE */
+ mlan_ds_misc_custom_ie ds_mgmt_ie;
+} MLAN_PACK_END HostCmd_DS_MGMT_IE_LIST_CFG;
+
+/** HostCmd_CMD_MAC_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** MAC register offset */
+ t_u16 offset;
+ /** MAC register value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MAC_REG_ACCESS;
+
+/** HostCmd_CMD_BBP_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_BBP_REG_ACCESS
+{
+ /** Acion */
+ t_u16 action;
+ /** BBP register offset */
+ t_u16 offset;
+ /** BBP register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_BBP_REG_ACCESS;
+
+/** HostCmd_CMD_RF_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_RF_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** RF register offset */
+ t_u16 offset;
+ /** RF register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_RF_REG_ACCESS;
+
+/** HostCmd_DS_802_11_EEPROM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_EEPROM_ACCESS
+{
+ /** Action */
+ t_u16 action;
+
+ /** multiple 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value;
+} MLAN_PACK_END HostCmd_DS_802_11_EEPROM_ACCESS;
+
+/** HostCmd_DS_MEM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MEM_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MEM_ACCESS;
+
+/** HostCmd_DS_SUBSCRIBE_EVENT */
+typedef MLAN_PACK_START struct _HostCmd_DS_SUBSCRIBE_EVENT
+{
+ /** Action */
+ t_u16 action;
+ /** Bitmap of subscribed events */
+ t_u16 event_bitmap;
+} MLAN_PACK_END HostCmd_DS_SUBSCRIBE_EVENT;
+
+/** HostCmd_DS_OTP_USER_DATA */
+typedef MLAN_PACK_START struct _HostCmd_DS_OTP_USER_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** User data length */
+ t_u16 user_data_length;
+ /** User data */
+ t_u8 user_data[1];
+} MLAN_PACK_END HostCmd_DS_OTP_USER_DATA;
+
+/** HostCmd_DS_INACTIVITY_TIMEOUT_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_INACTIVITY_TIMEOUT_EXT
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** uS, 0 means 1000uS(1ms) */
+ t_u16 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u16 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u16 mcast_timeout;
+ /** Timeout for additional RX traffic after Null PM1 packet exchange */
+ t_u16 ps_entry_timeout;
+ /** Reserved to further expansion */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_INACTIVITY_TIMEOUT_EXT;
+
+/** TLV type : STA Mac address */
+#define TLV_TYPE_STA_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 0x20) // 0x0120
+
+/** MrvlIEtypes_MacAddr_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_MacAddr_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_MacAddr_t;
+
+/** Assoc Request */
+#define SUBTYPE_ASSOC_REQUEST 0
+/** ReAssoc Request */
+#define SUBTYPE_REASSOC_REQUEST 2
+/** Probe Resp */
+#define SUBTYPE_PROBE_RESP 5
+/** Disassoc Request */
+#define SUBTYPE_DISASSOC 10
+/** Auth Request */
+#define SUBTYPE_AUTH 11
+/** Deauth Request */
+#define SUBTYPE_DEAUTH 12
+/** Action frame */
+#define SUBTYPE_ACTION 13
+
+#ifdef UAP_SUPPORT
+/** TLV type : AP Channel band Config */
+#define TLV_TYPE_UAP_CHAN_BAND_CONFIG (PROPRIETARY_TLV_BASE_ID + 0x2a) // 0x012a
+/** TLV type : AP Mac address */
+#define TLV_TYPE_UAP_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 0x2b) // 0x012b
+/** TLV type : AP Beacon period */
+#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 0x2c) // 0x012c
+/** TLV type : AP DTIM period */
+#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 0x2d) // 0x012d
+/** TLV type : AP Tx power */
+#define TLV_TYPE_UAP_TX_POWER (PROPRIETARY_TLV_BASE_ID + 0x2f) // 0x012f
+/** TLV type : AP SSID broadcast control */
+#define TLV_TYPE_UAP_BCAST_SSID_CTL (PROPRIETARY_TLV_BASE_ID + 0x30) // 0x0130
+/** TLV type : AP Preamble control */
+#define TLV_TYPE_UAP_PREAMBLE_CTL (PROPRIETARY_TLV_BASE_ID + 0x31) // 0x0131
+/** TLV type : AP Antenna control */
+#define TLV_TYPE_UAP_ANTENNA_CTL (PROPRIETARY_TLV_BASE_ID + 0x32) // 0x0132
+/** TLV type : AP RTS threshold */
+#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 0x33) // 0x0133
+/** TLV type : AP Tx data rate */
+#define TLV_TYPE_UAP_TX_DATA_RATE (PROPRIETARY_TLV_BASE_ID + 0x35) // 0x0135
+/** TLV type: AP Packet forwarding control */
+#define TLV_TYPE_UAP_PKT_FWD_CTL (PROPRIETARY_TLV_BASE_ID + 0x36) // 0x0136
+/** TLV type: STA information */
+#define TLV_TYPE_UAP_STA_INFO (PROPRIETARY_TLV_BASE_ID + 0x37) // 0x0137
+/** TLV type: AP STA MAC address filter */
+#define TLV_TYPE_UAP_STA_MAC_ADDR_FILTER (PROPRIETARY_TLV_BASE_ID + 0x38) // 0x0138
+/** TLV type: AP STA ageout timer */
+#define TLV_TYPE_UAP_STA_AGEOUT_TIMER (PROPRIETARY_TLV_BASE_ID + 0x39) // 0x0139
+/** TLV type: AP WEP keys */
+#define TLV_TYPE_UAP_WEP_KEY (PROPRIETARY_TLV_BASE_ID + 0x3b) // 0x013b
+/** TLV type: AP WPA passphrase */
+#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 0x3c) // 0x013c
+/** TLV type: AP protocol */
+#define TLV_TYPE_UAP_ENCRYPT_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 0x40) // 0x0140
+/** TLV type: AP AKMP */
+#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 0x41) // 0x0141
+/** TLV type: AP Fragment threshold */
+#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 0x46) // 0x0146
+/** TLV type: AP Group rekey timer */
+#define TLV_TYPE_UAP_GRP_REKEY_TIME (PROPRIETARY_TLV_BASE_ID + 0x47) // 0x0147
+/**TLV type : AP Max Station number */
+#define TLV_TYPE_UAP_MAX_STA_CNT (PROPRIETARY_TLV_BASE_ID + 0x55) // 0x0155
+/**TLV type : AP Retry limit */
+#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 0x5d) // 0x015d
+/** TLV type : AP MCBC data rate */
+#define TLV_TYPE_UAP_MCBC_DATA_RATE (PROPRIETARY_TLV_BASE_ID + 0x62) // 0x0162
+/**TLV type: AP RSN replay protection */
+#define TLV_TYPE_UAP_RSN_REPLAY_PROTECT (PROPRIETARY_TLV_BASE_ID + 0x64) // 0x0164
+/** TLV ID : Management Frame */
+#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 0x68) // 0x0168
+#ifdef UAP_SUPPORT
+/**TLV type: AP mgmt IE passthru mask */
+#define TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK (PROPRIETARY_TLV_BASE_ID + 0x70) // 0x0170
+#endif
+/** TLV : 20/40 coex config */
+#define TLV_TYPE_2040_BSS_COEX_CONTROL (PROPRIETARY_TLV_BASE_ID + 0x98) // 0x0198
+/**TLV type: AP pairwise handshake timeout */
+#define TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 0x75) // 0x0175
+/**TLV type: AP pairwise handshake retries */
+#define TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES (PROPRIETARY_TLV_BASE_ID + 0x76) // 0x0176
+/**TLV type: AP groupwise handshake timeout */
+#define TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 0x77) // 0x0177
+/**TLV type: AP groupwise handshake retries */
+#define TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES (PROPRIETARY_TLV_BASE_ID + 0x78) // 0x0178
+/** TLV type: AP PS STA ageout timer */
+#define TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER (PROPRIETARY_TLV_BASE_ID + 0x7b) // 0x017b
+/** TLV type : Pairwise Cipher */
+#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x91) // 0x0191
+/** TLV type : Group Cipher */
+#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x92) // 0x0192
+/** TLV type : BSS Status */
+#define TLV_TYPE_BSS_STATUS (PROPRIETARY_TLV_BASE_ID + 0x93) // 0x0193
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** TLV type : AP PSK */
+#define TLV_TYPE_UAP_PSK (PROPRIETARY_TLV_BASE_ID + 0xa8) // 0x01a8
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** MrvlIEtypes_beacon_period_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_beacon_period_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** beacon period */
+ t_u16 beacon_period;
+} MLAN_PACK_END MrvlIEtypes_beacon_period_t;
+
+/** MrvlIEtypes_dtim_period_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_dtim_period_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** DTIM period */
+ t_u8 dtim_period;
+} MLAN_PACK_END MrvlIEtypes_dtim_period_t;
+
+/** MrvlIEtypes_tx_rate_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_rate_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** tx data rate */
+ t_u16 tx_data_rate;
+} MLAN_PACK_END MrvlIEtypes_tx_rate_t;
+
+/** MrvlIEtypes_mcbc_rate_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mcbc_rate_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mcbc data rate */
+ t_u16 mcbc_data_rate;
+} MLAN_PACK_END MrvlIEtypes_mcbc_rate_t;
+
+/** MrvlIEtypes_tx_power_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_power_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** tx power */
+ t_u8 tx_power;
+} MLAN_PACK_END MrvlIEtypes_tx_power_t;
+
+/** MrvlIEtypes_bcast_ssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bcast_ssid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** bcast ssid control*/
+ t_u8 bcast_ssid_ctl;
+} MLAN_PACK_END MrvlIEtypes_bcast_ssid_t;
+
+/** MrvlIEtypes_antenna_mode_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_antenna_mode_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** which antenna */
+ t_u8 which_antenna;
+ /** antenna mode*/
+ t_u8 antenna_mode;
+} MLAN_PACK_END MrvlIEtypes_antenna_mode_t;
+
+/** MrvlIEtypes_pkt_forward_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_pkt_forward_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pkt foward control */
+ t_u8 pkt_forward_ctl;
+} MLAN_PACK_END MrvlIEtypes_pkt_forward_t;
+
+/** MrvlIEtypes_max_sta_count_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_max_sta_count_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** max station count */
+ t_u16 max_sta_count;
+} MLAN_PACK_END MrvlIEtypes_max_sta_count_t;
+
+/** MrvlIEtypes_sta_ageout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sta_ageout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station age out timer */
+ t_u32 sta_ageout_timer;
+} MLAN_PACK_END MrvlIEtypes_sta_ageout_t;
+
+/** MrvlIEtypes_rts_threshold_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_rts_threshold_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** rts threshold */
+ t_u16 rts_threshold;
+} MLAN_PACK_END MrvlIEtypes_rts_threshold_t;
+
+/** MrvlIEtypes_frag_threshold_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_frag_threshold_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** frag threshold */
+ t_u16 frag_threshold;
+} MLAN_PACK_END MrvlIEtypes_frag_threshold_t;
+
+/** MrvlIEtypes_retry_limit_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_retry_limit_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** retry limit */
+ t_u8 retry_limit;
+} MLAN_PACK_END MrvlIEtypes_retry_limit_t;
+
+/** MrvlIEtypes_eapol_pwk_hsk_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pwk_hsk_timeout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+} MLAN_PACK_END MrvlIEtypes_eapol_pwk_hsk_timeout_t;
+
+/** MrvlIEtypes_eapol_pwk_hsk_retries_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pwk_hsk_retries_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+} MLAN_PACK_END MrvlIEtypes_eapol_pwk_hsk_retries_t;
+
+/** MrvlIEtypes_eapol_gwk_hsk_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_gwk_hsk_timeout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+} MLAN_PACK_END MrvlIEtypes_eapol_gwk_hsk_timeout_t;
+
+/** MrvlIEtypes_eapol_gwk_hsk_retries_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_gwk_hsk_retries_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+} MLAN_PACK_END MrvlIEtypes_eapol_gwk_hsk_retries_t;
+
+#ifdef UAP_SUPPORT
+/** MrvlIEtypes_mgmt_ie_passthru_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mgmt_ie_passthru_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mgmt IE mask value */
+ t_u32 mgmt_ie_mask;
+} MLAN_PACK_END MrvlIEtypes_mgmt_ie_passthru_t;
+#endif
+
+/** TLV buffer : 2040 coex config */
+typedef MLAN_PACK_START struct _MrvlIEtypes_2040_coex_enable_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Enable */
+ t_u8 enable_2040coex;
+} MLAN_PACK_END MrvlIEtypes_2040_coex_enable_t;
+
+/** MrvlIEtypes_mac_filter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mac_filter_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Filter mode */
+ t_u8 filter_mode;
+ /** Number of STA MACs */
+ t_u8 count;
+ /** STA MAC addresses buffer */
+ t_u8 mac_address[1];
+} MLAN_PACK_END MrvlIEtypes_mac_filter_t;
+
+/** setting for band_config - band=5GHZ */
+#define BAND_CONFIG_5GHZ 0x01
+
+/** MrvlIEtypes_retry_limit_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_channel_band_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Band Configuration
+ *
+ * [7-6] Channel Selection Mode; 00 manual, 01 ACS
+ * [3-2] Channel Width; 00 20 MHz
+ * [1-0] Band Info; 00 2.4 GHz
+ */
+ t_u8 band_config;
+ /** channel */
+ t_u8 channel;
+} MLAN_PACK_END MrvlIEtypes_channel_band_t;
+
+/** MrvlIEtypes_auth_type_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_auth_type_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u8 auth_type;
+} MLAN_PACK_END MrvlIEtypes_auth_type_t;
+
+/** MrvlIEtypes_encrypt_protocol_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_encrypt_protocol_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** encryption protocol */
+ t_u16 protocol;
+} MLAN_PACK_END MrvlIEtypes_encrypt_protocol_t;
+
+/** MrvlIEtypes_pwk_cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_pwk_cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** protocol */
+ t_u16 protocol;
+ /** pairwise cipher */
+ t_u8 pairwise_cipher;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIEtypes_pwk_cipher_t;
+
+/** MrvlIEtypes_gwk_cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_gwk_cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIEtypes_gwk_cipher_t;
+
+/** MrvlIEtypes_akmp_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_akmp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** key management */
+ t_u16 key_mgmt;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+} MLAN_PACK_END MrvlIEtypes_akmp_t;
+
+/** MrvlIEtypes_passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_passphrase_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** passphrase */
+ t_u8 passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_passphrase_t;
+
+/** MrvlIEtypes_rsn_replay_prot_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_rsn_replay_prot_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** rsn replay proection */
+ t_u8 rsn_replay_prot;
+} MLAN_PACK_END MrvlIEtypes_rsn_replay_prot_t;
+
+/** MrvlIEtypes_group_rekey_time_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_group_rekey_time_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** group key rekey time */
+ t_u32 gk_rekey_time;
+} MLAN_PACK_END MrvlIEtypes_group_rekey_time_t;
+
+/** MrvlIEtypes_wep_key_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wep_key_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** key index */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** key data */
+ t_u8 key[1];
+} MLAN_PACK_END MrvlIEtypes_wep_key_t;
+
+/** MrvlIEtypes_bss_status_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bss_status_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSS status, READ only */
+ t_u16 bss_status;
+} MLAN_PACK_END MrvlIEtypes_bss_status_t;
+
+/** MrvlIEtypes_preamble_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_preamble_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** preamble type, READ only */
+ t_u8 preamble_type;
+} MLAN_PACK_END MrvlIEtypes_preamble_t;
+
+/** MrvlIEtypes_wmm_parameter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wmm_parameter_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM parameter */
+ WmmParameter_t wmm_para;
+} MLAN_PACK_END MrvlIEtypes_wmm_parameter_t;
+
+/** SNMP_MIB_UAP_INDEX */
+typedef enum _SNMP_MIB_UAP_INDEX
+{
+ tkip_mic_failures = 0x0b,
+ ccmp_decrypt_errors = 0x0c,
+ wep_undecryptable_count = 0x0d,
+ wep_icv_error_count = 0x0e,
+ decrypt_failure_count = 0xf,
+ dot11_failed_count = 0x12,
+ dot11_retry_count = 0x13,
+ dot11_multi_retry_count = 0x14,
+ dot11_frame_dup_count = 0x15,
+ dot11_rts_success_count = 0x16,
+ dot11_rts_failure_count = 0x17,
+ dot11_ack_failure_count = 0x18,
+ dot11_rx_fragment_count = 0x19,
+ dot11_mcast_rx_frame_count = 0x1a,
+ dot11_fcs_error_count = 0x1b,
+ dot11_tx_frame_count = 0x1c,
+ dot11_rsna_tkip_cm_invoked = 0x1d,
+ dot11_rsna_4way_hshk_failures = 0x1e,
+ dot11_mcast_tx_count = 0x1f,
+} SNMP_MIB_UAP_INDEX;
+
+/** MrvlIEtypes_snmp_oid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_snmp_oid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** data */
+ t_u32 data;
+} MLAN_PACK_END MrvlIEtypes_snmp_oid_t;
+
+/** HostCmd_SYS_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SYS_CONFIG
+{
+ /** CMD Action GET/SET*/
+ t_u16 action;
+ /** Tlv buffer */
+ t_u8 tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_SYS_CONFIG;
+
+/** HostCmd_SYS_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SYS_INFO
+{
+ /** sys info */
+ t_u8 sys_info[64];
+} MLAN_PACK_END HostCmd_DS_SYS_INFO;
+
+/** HostCmd_DS_STA_DEAUTH */
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_DEAUTH
+{
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ /** reason code */
+ t_u16 reason;
+} MLAN_PACK_END HostCmd_DS_STA_DEAUTH;
+
+/** Host Command id: POWER_MGMT */
+#define HOST_CMD_POWER_MGMT_EXT 0x00ef
+/** TLV type: AP Sleep param */
+#define TLV_TYPE_AP_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 0x6a) // 0x016a
+/** TLV type: AP Inactivity Sleep param */
+#define TLV_TYPE_AP_INACT_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 0x6b) // 0x016b
+
+/** MrvlIEtypes_sleep_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sleep_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** min_sleep */
+ t_u32 min_sleep;
+ /** max_sleep */
+ t_u32 max_sleep;
+} MLAN_PACK_END MrvlIEtypes_sleep_param_t;
+
+/** MrvlIEtypes_inact_sleep_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_inact_sleep_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** inactivity timeout */
+ t_u32 inactivity_to;
+
+ /** min_awake */
+ t_u32 min_awake;
+ /** max_awake */
+ t_u32 max_awake;
+} MLAN_PACK_END MrvlIEtypes_inact_sleep_param_t;
+
+/** HostCmd_DS_POWER_MGMT */
+typedef MLAN_PACK_START struct _HostCmd_DS_POWER_MGMT_EXT
+{
+ /** CMD Action Get/Set*/
+ t_u16 action;
+ /** power mode */
+ t_u16 power_mode;
+} MLAN_PACK_END HostCmd_DS_POWER_MGMT_EXT;
+
+/** MrvlIEtypes_ps_sta_ageout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ps_sta_ageout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station age out timer */
+ t_u32 ps_sta_ageout_timer;
+} MLAN_PACK_END MrvlIEtypes_ps_sta_ageout_t;
+
+/** MrvlIEtypes_sta_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sta_info_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mfg status */
+ t_u8 power_mfg_status;
+ /** RSSI */
+ t_s8 rssi;
+} MLAN_PACK_END MrvlIEtypes_sta_info_t;
+
+/** HostCmd_DS_STA_LIST */
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_LIST
+{
+ /** Number of STAs */
+ t_u16 sta_count;
+ /* MrvlIEtypes_sta_info_t sta_info[0]; */
+} MLAN_PACK_END HostCmd_DS_STA_LIST;
+
+/** TLV ID : WAPI Information */
+#define TLV_TYPE_AP_WAPI_INFO (PROPRIETARY_TLV_BASE_ID + 0x67) // 0x0167
+
+/** MrvlIEtypes_sta_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wapi_info_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Multicast PN */
+ t_u8 multicast_PN[16];
+} MLAN_PACK_END MrvlIEtypes_wapi_info_t;
+#endif /* UAP_SUPPORT */
+
+/**
+ * @brief 802.11h Local Power Constraint Marvell extended TLV
+ */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t header; /**< Marvell TLV header: ID/Len */
+ t_u8 chan; /**< Channel local constraint applies to */
+
+ /** Power constraint included in beacons and used by fw to offset 11d info */
+ t_u8 constraint;
+
+} MLAN_PACK_END MrvlIEtypes_LocalPowerConstraint_t;
+
+/*
+ *
+ * Data structures for driver/firmware command processing
+ *
+ */
+
+/** TPC Info structure sent in CMD_802_11_TPC_INFO command to firmware */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypes_LocalPowerConstraint_t local_constraint; /**< Local constraint */
+ MrvlIEtypes_PowerCapability_t power_cap; /**< Power Capability */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_INFO;
+
+/** TPC Request structure sent in CMD_802_11_TPC_ADAPT_REQ command to firmware */
+typedef MLAN_PACK_START struct
+{
+ t_u8 dest_mac[MLAN_MAC_ADDR_LENGTH]; /**< Destination STA address */
+ t_u16 timeout; /**< Response timeout in ms */
+ t_u8 rate_index; /**< IEEE Rate index to send request */
+
+} MLAN_PACK_END HostCmd_TpcRequest;
+
+/** TPC Response structure received from the CMD_802_11_TPC_ADAPT_REQ command */
+typedef MLAN_PACK_START struct
+{
+ t_u8 tpc_ret_code; /**< Firmware command result status code */
+ t_s8 tx_power; /**< Reported TX Power from the TPC Report element */
+ t_s8 link_margin; /**< Reported link margin from the TPC Report element */
+ t_s8 rssi; /**< RSSI of the received TPC Report frame */
+
+} MLAN_PACK_END HostCmd_TpcResponse;
+
+/** CMD_802_11_TPC_ADAPT_REQ substruct. Union of the TPC request and response */
+typedef MLAN_PACK_START union
+{
+ HostCmd_TpcRequest req; /**< Request struct sent to firmware */
+ HostCmd_TpcResponse resp; /**< Response struct received from firmware */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_ADAPT_REQ;
+
+/** CMD_802_11_CHAN_SW_ANN firmware command substructure */
+typedef MLAN_PACK_START struct
+{
+ t_u8 switch_mode; /**< Set to 1 for a quiet switch request, no STA tx */
+ t_u8 new_chan; /**< Requested new channel */
+ t_u8 switch_count; /**< Number of TBTTs until the switch is to occur */
+} MLAN_PACK_END HostCmd_DS_802_11_CHAN_SW_ANN;
+
+/**
+ * @brief Enumeration of measurement types, including max supported
+ * enum for 11h/11k
+ */
+typedef MLAN_PACK_START enum _MeasType_t
+{
+ WLAN_MEAS_BASIC = 0, /**< 11h: Basic */
+ WLAN_MEAS_NUM_TYPES, /**< Number of enumerated measurements */
+ WLAN_MEAS_11H_MAX_TYPE = WLAN_MEAS_BASIC, /**< Max 11h measurement */
+
+} MLAN_PACK_END MeasType_t;
+
+/**
+ * @brief Mode octet of the measurement request element (7.3.2.21)
+ */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 duration_mandatory:1; /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 report:1; /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 request:1; /**< 11h: en/disable requests of specified type */
+ t_u8 enable:1; /**< 11h: enable report/request bits */
+ t_u8 parallel:1; /**< 11k: series or parallel with previous meas */
+#else
+ t_u8 parallel:1; /**< 11k: series or parallel with previous meas */
+ t_u8 enable:1; /**< 11h: enable report/request bits */
+ t_u8 request:1; /**< 11h: en/disable requests of specified type */
+ t_u8 report:1; /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 duration_mandatory:1; /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasReqMode_t;
+
+/**
+ * @brief Common measurement request structure (7.3.2.21.1 to 7.3.2.21.3)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measure */
+ t_u64 start_time; /**< TSF Start time of measurement (0 for immediate) */
+ t_u16 duration; /**< TU duration of the measurement */
+
+} MLAN_PACK_END MeasReqCommonFormat_t;
+
+/**
+ * @brief Basic measurement request structure (7.3.2.21.1)
+ */
+typedef MeasReqCommonFormat_t MeasReqBasic_t;
+
+/**
+ * @brief CCA measurement request structure (7.3.2.21.2)
+ */
+typedef MeasReqCommonFormat_t MeasReqCCA_t;
+
+/**
+ * @brief RPI measurement request structure (7.3.2.21.3)
+ */
+typedef MeasReqCommonFormat_t MeasReqRPI_t;
+
+/**
+ * @brief Union of the availble measurement request types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union
+{
+ MeasReqBasic_t basic; /**< Basic measurement request */
+ MeasReqCCA_t cca; /**< CCA measurement request */
+ MeasReqRPI_t rpi; /**< RPI measurement request */
+
+} MeasRequest_t;
+
+/**
+ * @brief Mode octet of the measurement report element (7.3.2.22)
+ */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd3_7:5; /**< Reserved */
+ t_u8 refused:1; /**< Measurement refused */
+ t_u8 incapable:1; /**< Incapable of performing measurement */
+ t_u8 late:1; /**< Start TSF time missed for measurement */
+#else
+ t_u8 late:1; /**< Start TSF time missed for measurement */
+ t_u8 incapable:1; /**< Incapable of performing measurement */
+ t_u8 refused:1; /**< Measurement refused */
+ t_u8 rsvd3_7:5; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptMode_t;
+
+/**
+ * @brief Basic measurement report (7.3.2.22.1)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ MeasRptBasicMap_t map; /**< Basic measurement report */
+
+} MLAN_PACK_END MeasRptBasic_t;
+
+/**
+ * @brief CCA measurement report (7.3.2.22.2)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 busy_fraction; /**< Fractional duration CCA indicated chan busy */
+
+} MLAN_PACK_END MeasRptCCA_t;
+
+/**
+ * @brief RPI measurement report (7.3.2.22.3)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 density[8]; /**< RPI Density histogram report */
+
+} MLAN_PACK_END MeasRptRPI_t;
+
+/**
+ * @brief Union of the availble measurement report types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union
+{
+ MeasRptBasic_t basic; /**< Basic measurement report */
+ MeasRptCCA_t cca; /**< CCA measurement report */
+ MeasRptRPI_t rpi; /**< RPI measurement report */
+
+} MeasReport_t;
+
+/**
+ * @brief Structure passed to firmware to perform a measurement
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog toke */
+ MeasReqMode_t req_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasRequest_t req; /**< Measurement request data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REQUEST;
+
+/**
+ * @brief Structure passed back from firmware with a measurement report,
+ * also can be to send a measurement report to another STA
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog token */
+ MeasRptMode_t rpt_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasReport_t rpt; /**< Measurement report data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REPORT;
+
+typedef MLAN_PACK_START struct
+{
+ t_u16 startFreq;
+ t_u8 chanWidth;
+ t_u8 chanNum;
+
+} MLAN_PACK_END MrvlChannelDesc_t;
+
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t Header; /**< Header */
+
+ MeasRptBasicMap_t map; /**< IEEE 802.11h basic meas report */
+} MLAN_PACK_END MrvlIEtypes_ChanRpt11hBasic_t;
+
+typedef MLAN_PACK_START struct
+{
+ MrvlChannelDesc_t chan_desc; /**< Channel band, number */
+ t_u32 millisec_dwell_time; /**< Channel dwell time in milliseconds */
+} MLAN_PACK_END HostCmd_DS_CHAN_RPT_REQ;
+
+typedef MLAN_PACK_START struct
+{
+ t_u32 cmd_result; /**< Rpt request command result (0 == SUCCESS) */
+ t_u64 start_tsf; /**< TSF Measurement started */
+ t_u32 duration; /**< Duration of measurement in microsecs */
+ t_u8 tlv_buffer[1]; /**< TLV Buffer */
+} MLAN_PACK_END HostCmd_DS_CHAN_RPT_RSP;
+
+/** statistics threshold */
+typedef MLAN_PACK_START struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** value */
+ t_u8 value;
+ /** reporting frequency */
+ t_u8 frequency;
+} MLAN_PACK_END MrvlIEtypes_BeaconHighRssiThreshold_t,
+ MrvlIEtypes_BeaconLowRssiThreshold_t,
+ MrvlIEtypes_BeaconHighSnrThreshold_t,
+ MrvlIEtypes_BeaconLowSnrThreshold_t,
+ MrvlIEtypes_FailureCount_t,
+ MrvlIEtypes_DataLowRssiThreshold_t,
+ MrvlIEtypes_DataHighRssiThreshold_t,
+ MrvlIEtypes_DataLowSnrThreshold_t,
+ MrvlIEtypes_DataHighSnrThreshold_t,
+ MrvlIETypes_PreBeaconMissed_t, MrvlIEtypes_BeaconsMissed_t;
+
+/** statistics threshold for LinkQuality */
+typedef MLAN_PACK_START struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /** Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+} MLAN_PACK_END MrvlIEtypes_LinkQualityThreshold_t;
+
+/** HostCmd_DS_COMMAND */
+typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND
+{
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command Body */
+ union
+ {
+ /** Hardware specifications */
+ HostCmd_DS_GET_HW_SPEC hw_spec;
+ /** Cfg data */
+ HostCmd_DS_802_11_CFG_DATA cfg_data;
+ /** MAC control */
+ HostCmd_DS_MAC_CONTROL mac_ctrl;
+ /** MAC address */
+ HostCmd_DS_802_11_MAC_ADDRESS mac_addr;
+ /** MAC muticast address */
+ HostCmd_DS_MAC_MULTICAST_ADR mc_addr;
+ /** Get log */
+ HostCmd_DS_802_11_GET_LOG get_log;
+ /** RSSI information */
+ HostCmd_DS_802_11_RSSI_INFO rssi_info;
+ /** RSSI information response */
+ HostCmd_DS_802_11_RSSI_INFO_RSP rssi_info_rsp;
+ /** SNMP MIB */
+ HostCmd_DS_802_11_SNMP_MIB smib;
+ /** Radio control */
+ HostCmd_DS_802_11_RADIO_CONTROL radio;
+ /** RF channel */
+ HostCmd_DS_802_11_RF_CHANNEL rf_channel;
+ /** Tx rate query */
+ HostCmd_TX_RATE_QUERY tx_rate;
+ /** Tx rate configuration */
+ HostCmd_DS_TX_RATE_CFG tx_rate_cfg;
+ /** Tx power configuration */
+ HostCmd_DS_TXPWR_CFG txp_cfg;
+ /** RF Tx power configuration */
+ HostCmd_DS_802_11_RF_TX_POWER txp;
+
+ /** RF antenna */
+ HostCmd_DS_802_11_RF_ANTENNA antenna;
+ /** Enhanced power save command */
+ HostCmd_DS_802_11_PS_MODE_ENH psmode_enh;
+ HostCmd_DS_802_11_HS_CFG_ENH opt_hs_cfg;
+ /** Scan */
+ HostCmd_DS_802_11_SCAN scan;
+ /** Extended Scan */
+ HostCmd_DS_802_11_SCAN_EXT ext_scan;
+
+ /** Mgmt frame subtype mask */
+ HostCmd_DS_RX_MGMT_IND rx_mgmt_ind;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+
+ HostCmd_DS_802_11_BG_SCAN_CONFIG bg_scan_config;
+ HostCmd_DS_802_11_BG_SCAN_QUERY bg_scan_query;
+ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bg_scan_query_resp;
+ HostCmd_DS_SUBSCRIBE_EVENT subscribe_event;
+ HostCmd_DS_OTP_USER_DATA otp_user_data;
+ /** Associate */
+ HostCmd_DS_802_11_ASSOCIATE associate;
+
+ /** Associate response */
+ HostCmd_DS_802_11_ASSOCIATE_RSP associate_rsp;
+ /** Deauthenticate */
+ HostCmd_DS_802_11_DEAUTHENTICATE deauth;
+ /** Ad-Hoc start */
+ HostCmd_DS_802_11_AD_HOC_START adhoc_start;
+ /** Ad-Hoc start result */
+ HostCmd_DS_802_11_AD_HOC_START_RESULT adhoc_start_result;
+ /** Ad-Hoc join result */
+ HostCmd_DS_802_11_AD_HOC_JOIN_RESULT adhoc_join_result;
+ /** Ad-Hoc join */
+ HostCmd_DS_802_11_AD_HOC_JOIN adhoc_join;
+ /** Domain information */
+ HostCmd_DS_802_11D_DOMAIN_INFO domain_info;
+ /** Domain information response */
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP domain_info_resp;
+ HostCmd_DS_802_11_TPC_ADAPT_REQ tpc_req;
+ HostCmd_DS_802_11_TPC_INFO tpc_info;
+ HostCmd_DS_802_11_CHAN_SW_ANN chan_sw_ann;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+ HostCmd_DS_MEASUREMENT_REQUEST meas_req;
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt;
+ /** Add BA request */
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ /** Add BA response */
+ HostCmd_DS_11N_ADDBA_RSP add_ba_rsp;
+ /** Delete BA entry */
+ HostCmd_DS_11N_DELBA del_ba;
+ /** Tx buffer configuration */
+ HostCmd_DS_TXBUF_CFG tx_buf;
+ /** AMSDU Aggr Ctrl configuration */
+ HostCmd_DS_AMSDU_AGGR_CTRL amsdu_aggr_ctrl;
+ /** 11n configuration */
+ HostCmd_DS_11N_CFG htcfg;
+ /** 11n configuration */
+ HostCmd_DS_TX_BF_CFG tx_bf_cfg;
+ /** WMM status get */
+ HostCmd_DS_WMM_GET_STATUS get_wmm_status;
+ /** WMM ADDTS */
+ HostCmd_DS_WMM_ADDTS_REQ add_ts;
+ /** WMM DELTS */
+ HostCmd_DS_WMM_DELTS_REQ del_ts;
+ /** WMM set/get queue config */
+ HostCmd_DS_WMM_QUEUE_CONFIG queue_config;
+ /** WMM on/of/get queue statistics */
+ HostCmd_DS_WMM_QUEUE_STATS queue_stats;
+ /** WMM get traffic stream status */
+ HostCmd_DS_WMM_TS_STATUS ts_status;
+ /** Key material */
+ HostCmd_DS_802_11_KEY_MATERIAL key_material;
+ /** E-Supplicant PSK */
+ HostCmd_DS_802_11_SUPPLICANT_PMK esupplicant_psk;
+ /** E-Supplicant profile */
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE esupplicant_profile;
+ /** Extended version */
+ HostCmd_DS_VERSION_EXT verext;
+ /** Adhoc Coalescing */
+ HostCmd_DS_802_11_IBSS_STATUS ibss_coalescing;
+ /** Mgmt IE list configuration */
+ HostCmd_DS_MGMT_IE_LIST_CFG mgmt_ie_list;
+ /** System clock configuration */
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG sys_clock_cfg;
+ /** MAC register access */
+ HostCmd_DS_MAC_REG_ACCESS mac_reg;
+ /** BBP register access */
+ HostCmd_DS_BBP_REG_ACCESS bbp_reg;
+ /** RF register access */
+ HostCmd_DS_RF_REG_ACCESS rf_reg;
+ /** EEPROM register access */
+ HostCmd_DS_802_11_EEPROM_ACCESS eeprom;
+ /** Memory access */
+ HostCmd_DS_MEM_ACCESS mem;
+
+ /** Inactivity timeout extend */
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT inactivity_to;
+#ifdef UAP_SUPPORT
+ HostCmd_DS_SYS_CONFIG sys_config;
+ HostCmd_DS_SYS_INFO sys_info;
+ HostCmd_DS_STA_DEAUTH sta_deauth;
+ HostCmd_DS_STA_LIST sta_list;
+ HostCmd_DS_POWER_MGMT_EXT pm_cfg;
+#endif /* UAP_SUPPORT */
+
+ /** Sleep period command */
+ HostCmd_DS_802_11_SLEEP_PERIOD sleep_pd;
+ /** Sleep params command */
+ HostCmd_DS_802_11_SLEEP_PARAMS sleep_param;
+
+ /** SDIO GPIO interrupt config command */
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_gpio_int;
+ HostCmd_DS_SDIO_PULL_CTRL sdio_pull_ctl;
+ HostCmd_DS_SET_BSS_MODE bss_mode;
+ HostCmd_DS_CMD_TX_DATA_PAUSE tx_data_pause;
+#ifdef WIFI_DIRECT_SUPPORT
+ HostCmd_DS_REMAIN_ON_CHANNEL remain_on_chan;
+ HostCmd_DS_WIFI_DIRECT_MODE wifi_direct_mode;
+#endif
+ } params;
+} MLAN_PACK_END HostCmd_DS_COMMAND;
+
+/** PS_CMD_ConfirmSleep */
+typedef MLAN_PACK_START struct _OPT_Confirm_Sleep
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+ /** Action */
+ t_u16 action;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+} MLAN_PACK_END OPT_Confirm_Sleep;
+
+typedef struct MLAN_PACK_START _opt_sleep_confirm_buffer
+{
+ /** Header for interface */
+ t_u8 hdr[4];
+ /** New power save command used to send sleep confirmation to the firmware */
+ OPT_Confirm_Sleep ps_cfm_sleep;
+} MLAN_PACK_END opt_sleep_confirm_buffer;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+#endif /* !_MLAN_FW_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_ieee.h b/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
new file mode 100644
index 000000000000..2431e06f48fa
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
@@ -0,0 +1,1322 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ * 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/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** FIX IES size in beacon buffer */
+#define WLAN_802_11_FIXED_IE_SIZE 12
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension*/
+#define WLAN_SUPPORTED_RATES_EXT 32
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound */
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0xF000) >> 12)
+#else
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0x00F0) >> 4)
+#endif
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+
+#ifdef STA_SUPPORT
+ COUNTRY_INFO = 7,
+#endif /* STA_SUPPORT */
+
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ SUPPORTED_CHANNELS = 36,
+ CHANNEL_SWITCH_ANN = 37,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+
+ WPA_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t
+{
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+}
+MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+}
+MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | \
+ MBIT(12) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ t_u8 rsrvd1:2;
+ t_u8 dsss_ofdm:1;
+ t_u8 rsvrd2:2;
+ t_u8 short_slot_time:1;
+ t_u8 rsrvd3:1;
+ t_u8 spectrum_mgmt:1;
+ t_u8 chan_agility:1;
+ t_u8 pbcc:1;
+ t_u8 short_preamble:1;
+ t_u8 privacy:1;
+ t_u8 cf_poll_rqst:1;
+ t_u8 cf_pollable:1;
+ t_u8 ibss:1;
+ t_u8 ess:1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t
+{
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value in milliseconds */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t
+{
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t
+{
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time in milliseconds */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t
+{
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t
+{
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t
+{
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** cipher TKIP */
+#define WPA_CIPHER_TKIP 2
+/** cipher AES */
+#define WPA_CIPHER_AES_CCM 4
+/** AKM: 8021x */
+#define RSN_AKM_8021X 1
+/** AKM: PSK */
+#define RSN_AKM_PSK 2
+
+/** wpa_suite_t */
+typedef MLAN_PACK_START struct _wpa_suite_t
+{
+ /** OUI */
+ t_u8 oui[3];
+ /** tyep */
+ t_u8 type;
+} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t;
+
+/** wpa_suite_ucast_t */
+typedef MLAN_PACK_START struct
+{
+ /* count */
+ t_u16 count;
+ /** wpa_suite list */
+ wpa_suite list[1];
+} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+
+/** IEEEtypes_Rsn_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t
+{
+ /** Rsn : Element ID */
+ t_u8 element_id;
+ /** Rsn : Length */
+ t_u8 len;
+ /** Rsn : version */
+ t_u16 version;
+ /** Rsn : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Rsn : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t;
+
+/** IEEEtypes_Wpa_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t
+{
+ /** Wpa : Element ID */
+ t_u8 element_id;
+ /** Wpa : Length */
+ t_u8 len;
+ /** Wpa : oui */
+ t_u8 oui[4];
+ /** version */
+ t_u16 version;
+ /** Wpa : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Wpa : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t;
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t
+{
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t
+{
+
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t
+{
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Enumerator for TSPEC direction */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e
+{
+
+ TSPEC_DIR_UPLINK = 0,
+ TSPEC_DIR_DOWNLINK = 1,
+ /* 2 is a reserved value */
+ TSPEC_DIR_BIDIRECT = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e;
+
+/** Enumerator for TSPEC PSB */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e
+{
+
+ TSPEC_PSB_LEGACY = 0,
+ TSPEC_PSB_TRIG = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e;
+
+/** Enumerator for TSPEC Ack Policy */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e
+{
+
+ TSPEC_ACKPOLICY_NORMAL = 0,
+ TSPEC_ACKPOLICY_NOACK = 1,
+ /* 2 is reserved */
+ TSPEC_ACKPOLICY_BLOCKACK = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e;
+
+/** Enumerator for TSPEC Trafffice type */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e
+{
+
+ TSPEC_TRAFFIC_APERIODIC = 0,
+ TSPEC_TRAFFIC_PERIODIC = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e;
+
+/** Data structure of WMM TSPEC information */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 Reserved17_23:7; // ! Reserved
+ t_u8 Schedule:1;
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 Aggregation:1; // ! Reserved
+ t_u8 AccessPolicy2:1; // !
+ t_u8 AccessPolicy1:1; // !
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+#else
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 AccessPolicy1:1; // !
+ t_u8 AccessPolicy2:1; // !
+ t_u8 Aggregation:1; // ! Reserved
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 Schedule:1;
+ t_u8 Reserved17_23:7; // ! Reserved
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t;
+
+/** Data structure of WMM TSPEC Nominal Size */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+ t_u16 Size:15; // ! Nominal size in octets
+#else
+ t_u16 Size:15; // ! Nominal size in octets
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t;
+
+/** Data structure of WMM TSPEC SBWA */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Whole:3; // ! Whole portion
+ t_u16 Fractional:13; // ! Fractional portion
+#else
+ t_u16 Fractional:13; // ! Fractional portion
+ t_u16 Whole:3; // ! Whole portion
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA;
+
+/** Data structure of WMM TSPEC Body */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo;
+ IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize;
+ t_u16 MaximumMSDUSize;
+ t_u32 MinServiceInterval;
+ t_u32 MaxServiceInterval;
+ t_u32 InactivityInterval;
+ t_u32 SuspensionInterval;
+ t_u32 ServiceStartTime;
+ t_u32 MinimumDataRate;
+ t_u32 MeanDataRate;
+ t_u32 PeakDataRate;
+ t_u32 MaxBurstSize;
+ t_u32 DelayBound;
+ t_u32 MinPHYRate;
+ IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance;
+ t_u16 MediumTime;
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t;
+
+/** Data structure of WMM TSPEC all elements */
+typedef MLAN_PACK_START struct
+{
+ t_u8 ElementId;
+ t_u8 Len;
+ t_u8 OuiType[4]; /* 00:50:f2:02 */
+ t_u8 OuiSubType; /* 01 */
+ t_u8 Version;
+
+ IEEEtypes_WMM_TSPEC_Body_t TspecBody;
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t;
+
+/** WMM Action Category values */
+typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e
+{
+
+ IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0,
+ IEEE_MGMT_ACTION_CATEGORY_QOS = 1,
+ IEEE_MGMT_ACTION_CATEGORY_DLS = 2,
+ IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3,
+ IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4,
+ IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5,
+ IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6,
+ IEEE_MGMT_ACTION_CATEGORY_HT = 7,
+
+ IEEE_MGMT_ACTION_CATEGORY_WNM = 10,
+ IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11,
+
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17
+} MLAN_PACK_END IEEEtypes_ActionCategory_e;
+
+/** WMM TSPEC operations */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e
+{
+
+ TSPEC_ACTION_CODE_ADDTS_REQ = 0,
+ TSPEC_ACTION_CODE_ADDTS_RSP = 1,
+ TSPEC_ACTION_CODE_DELTS = 2,
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e;
+
+/** WMM TSPEC Category Action Base */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_ActionCategory_e category;
+ IEEEtypes_WMM_Tspec_Action_e action;
+ t_u8 dialogToken;
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t;
+
+/** WMM TSPEC AddTS request structure */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t;
+
+/** WMM TSPEC AddTS response structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t;
+
+/** WMM TSPEC DelTS structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 reasonCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t;
+
+/** union of WMM TSPEC structures */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+
+ IEEEtypes_Action_WMM_AddTsReq_t addTsReq;
+ IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t delTs;
+
+} MLAN_PACK_END IEEEtypes_Action_WMMAC_t;
+
+/** union of WMM TSPEC & Action category */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_ActionCategory_e category;
+
+ IEEEtypes_Action_WMMAC_t wmmAc;
+
+} MLAN_PACK_END IEEEtypes_ActionFrame_t;
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+#ifdef STA_SUPPORT
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+#endif /* STA_SUPPORT */
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t
+{
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t
+{
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t
+{
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t
+{
+ /** Extended Capabilities value */
+ t_u8 ext_cap_value;
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t
+{
+ /** OBSS Scan Passive Dwell in milliseconds */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell in milliseconds */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval in seconds */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/* IEEE Channel Switch Announcement Element (7.3.2.20) */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a chan switch element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 37 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */
+ t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */
+ t_u8 chan_switch_count; /**< # of TBTTs before channel switch */
+
+} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+#else
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct
+{
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch Announcement IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+#ifdef STA_SUPPORT
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Scan all the channels in specified band */
+#define BAND_SPECIFIED 0x80
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid
+{
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan
+{
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 1, Passive = 2 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief Reserved
+ */
+ t_u8 reserved;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/** Default scan interval in millisecond*/
+#define DEFAULT_BGSCAN_INTERVAL 30000
+
+/** action get all, except pps/uapsd config */
+#define BG_SCAN_ACT_GET 0x0000
+/** action set all, except pps/uapsd config */
+#define BG_SCAN_ACT_SET 0x0001
+/** action get pps/uapsd config */
+#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100
+/** action set pps/uapsd config */
+#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101
+/** action set all */
+#define BG_SCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define BG_SCAN_SSID_MATCH 0x0001
+/** ssid match and RSSI exceeded */
+#define BG_SCAN_SSID_RSSI_MATCH 0x0004
+/** Maximum number of channels that can be sent in bg scan config */
+#define WLAN_BG_SCAN_CHAN_MAX 32
+
+/**
+ * Input structure to configure bs scan cmd to firmware
+ */
+typedef MLAN_PACK_START struct
+{
+ /** action */
+ t_u16 action;
+ /** enable/disable */
+ t_u8 enable;
+ /** BSS type:
+ * MLAN_SCAN_MODE_BSS (infrastructure)
+ * MLAN_SCAN_MODE_IBSS (adhoc)
+ * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_type;
+ /** number of channel scanned during each scan */
+ t_u8 chan_per_scan;
+ /** interval between consecutive scan */
+ t_u32 scan_interval;
+ /** bit 0: ssid match bit 1: ssid match and SNR exceeded
+ * bit 2: ssid match and RSSI exceeded
+ * bit 31: wait for all channel scan to complete to report scan result
+ */
+ t_u32 report_condition;
+ /* Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+ /** RSSI threshold */
+ t_u8 rssi_threshold;
+ /** SNR threshold */
+ t_u8 snr_threshold;
+ /** repeat count */
+ t_u16 repeat_count;
+ /** SSID filter list used in the to limit the scan results */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_bgscan_cfg;
+#endif /* STA_SUPPORT */
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t
+{
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** Indicate disabling 11n when associate with AP */
+ t_u8 disable_11n;
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+#ifdef STA_SUPPORT
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+#endif /* STA_SUPPORT */
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+#ifdef STA_SUPPORT
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+#endif
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_init.c b/drivers/net/wireless/sd8797/mlan/mlan_init.c
new file mode 100644
index 000000000000..48681b3e3ed9
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_init.c
@@ -0,0 +1,1043 @@
+/** @file mlan_init.c
+ *
+ * @brief This file contains the initialization for FW
+ * and HW.
+ *
+ * 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
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_meas.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function adds a BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_add_bsspriotbl(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((status =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_bssprio_node),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pbssprio))) {
+ PRINTM(MERROR, "Failed to allocate bsspriotbl\n");
+ LEAVE();
+ return status;
+ }
+
+ pbssprio->priv = priv;
+
+ util_init_list((pmlan_linked_list) pbssprio);
+
+ if (!pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur)
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = pbssprio;
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[priv->
+ bss_priority].bssprio_head,
+ (pmlan_linked_list) pbssprio,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function deletes the BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_delete_bsspriotbl(pmlan_private priv)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio_node = MNULL, *ptmp_node = MNULL, **ppcur =
+ MNULL;
+ pmlan_list_head phead;
+
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ phead = &pmadapter->bssprio_tbl[i].bssprio_head;
+ ppcur = &pmadapter->bssprio_tbl[i].bssprio_cur;
+ PRINTM(MINFO,
+ "Delete BSS priority table, index = %d, i = %d, phead = %p, pcur = %p\n",
+ priv->bss_index, i, phead, *ppcur);
+ if (*ppcur) {
+ pbssprio_node =
+ (mlan_bssprio_node *) util_peek_list(pmadapter->pmoal_handle,
+ phead,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+ while (pbssprio_node && ((pmlan_list_head) pbssprio_node != phead)) {
+ ptmp_node = pbssprio_node->pnext;
+ if (pbssprio_node->priv == priv) {
+ PRINTM(MINFO, "Delete node, pnode = %p, pnext = %p\n",
+ pbssprio_node, ptmp_node);
+ util_unlink_list(pmadapter->pmoal_handle, phead,
+ (pmlan_linked_list) pbssprio_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pbssprio_node);
+ }
+ pbssprio_node = ptmp_node;
+ }
+ *ppcur = (mlan_bssprio_node *) phead;
+ }
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function allocates buffer for the members of adapter
+ * structure like command buffer and BSSID list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_allocate_adapter(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ t_u32 buf_size;
+ BSSDescriptor_t *ptemp_scan_table = MNULL;
+#endif
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ /* Allocate buffer to store the BSSID list */
+ buf_size = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
+ ret =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF,
+ (t_u8 **) & ptemp_scan_table);
+ if (ret != MLAN_STATUS_SUCCESS || !ptemp_scan_table) {
+ PRINTM(MERROR, "Failed to allocate scan table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pscan_table = ptemp_scan_table;
+ ret =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ DEFAULT_SCAN_BEACON_BUFFER,
+ MLAN_MEM_DEF,
+ (t_u8 **) & pmadapter->bcn_buf);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->bcn_buf) {
+ PRINTM(MERROR, "Failed to allocate bcn buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->bcn_buf_size = DEFAULT_SCAN_BEACON_BUFFER;
+#endif
+
+ /* Allocate command buffer */
+ ret = wlan_alloc_cmd_buffer(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate command buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ ret =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ MAX_MP_REGS + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **) & pmadapter->mp_regs_buf);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mp_regs_buf) {
+ PRINTM(MERROR, "Failed to allocate mp_regs_buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->mp_regs =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mp_regs_buf, DMA_ALIGNMENT);
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ ret = wlan_alloc_sdio_mpa_buffers(pmadapter, SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
+ SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+
+ pmadapter->psleep_cfm =
+ wlan_alloc_mlan_buffer(pmadapter, sizeof(opt_sleep_confirm_buffer), 0,
+ MTRUE);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function initializes the private structure
+ * and sets default values to the members of mlan_private.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_init_priv(pmlan_private priv)
+{
+ t_u32 i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ priv->media_connected = MFALSE;
+ memset(pmadapter, priv->curr_addr, 0xff, MLAN_MAC_ADDR_LENGTH);
+
+#ifdef STA_SUPPORT
+ priv->pkt_tx_ctrl = 0;
+ priv->bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->data_rate = 0; /* Initially indicate the rate as auto */
+ priv->is_data_rate_auto = MTRUE;
+ priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ priv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ priv->sec_info.authentication_mode = MLAN_AUTH_MODE_AUTO;
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+ for (i = 0; i < sizeof(priv->wep_key) / sizeof(priv->wep_key[0]); i++)
+ memset(pmadapter, &priv->wep_key[i], 0, sizeof(mrvl_wep_key_t));
+ priv->wep_key_curr_index = 0;
+ priv->ewpa_query = MFALSE;
+ priv->adhoc_aes_enabled = MFALSE;
+ priv->curr_pkt_filter =
+ HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
+ HostCmd_ACT_MAC_ETHERNETII_ENABLE;
+
+ priv->beacon_period = MLAN_BEACON_INTERVAL;
+ priv->pattempted_bss_desc = MNULL;
+ memset(pmadapter, &priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
+ priv->listen_interval = MLAN_DEFAULT_LISTEN_INTERVAL;
+
+ memset(pmadapter, &priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
+ priv->assoc_rsp_size = 0;
+
+ wlan_11d_priv_init(priv);
+ wlan_11h_priv_init(priv);
+#if defined(UAP_SUPPORT)
+ priv->uap_bss_started = MFALSE;
+ memset(pmadapter, &priv->uap_state_chan_cb, 0,
+ sizeof(priv->uap_state_chan_cb));
+#endif
+#if defined(UAP_SUPPORT)
+ priv->num_drop_pkts = 0;
+#endif
+#if defined(STA_SUPPORT)
+ priv->adhoc_state_prev = ADHOC_IDLE;
+ memset(pmadapter, &priv->adhoc_last_start_ssid, 0,
+ sizeof(priv->adhoc_last_start_ssid));
+#endif
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->atim_window = 0;
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->tx_power_level = 0;
+ priv->max_tx_power_level = 0;
+ priv->min_tx_power_level = 0;
+ priv->tx_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->rxpd_rate = 0;
+ priv->rate_bitmap = 0;
+ priv->data_rssi_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->data_nf_last = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->bcn_nf_last = 0;
+
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ memset(pmadapter, &priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ memset(pmadapter, &priv->aes_key, 0, sizeof(priv->aes_key));
+ priv->wpa_ie_len = 0;
+ priv->wpa_is_gtk_set = MFALSE;
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
+
+ memset(pmadapter, &priv->wps, 0, sizeof(priv->wps));
+ memset(pmadapter, &priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
+ priv->gen_ie_buf_len = 0;
+#endif /* STA_SUPPORT */
+
+ priv->tx_bf_cap = 0;
+ priv->wmm_required = MTRUE;
+ priv->wmm_enabled = MFALSE;
+ priv->wmm_qosinfo = 0;
+#ifdef STA_SUPPORT
+ priv->pcurr_bcn_buf = MNULL;
+ priv->curr_bcn_size = 0;
+#endif /* STA_SUPPORT */
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ priv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+ priv->max_amsdu = 0;
+
+ priv->scan_block = MFALSE;
+
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->port_ctrl_mode = MTRUE;
+ } else {
+ priv->port_ctrl_mode = MFALSE;
+ }
+ priv->port_open = MFALSE;
+
+ if (!ret)
+ ret = wlan_add_bsspriotbl(priv);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the adapter structure
+ * and sets default values to the members of adapter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_init_adapter(pmlan_adapter pmadapter)
+{
+ opt_sleep_confirm_buffer *sleep_cfm_buf = MNULL;
+
+ ENTER();
+
+ sleep_cfm_buf = (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->
+ data_offset);
+
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->init_para.mfg_mode == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->mfg_mode = MFALSE;
+ } else {
+ pmadapter->mfg_mode = pmadapter->init_para.mfg_mode;
+ }
+#endif
+
+ pmadapter->int_mode = pmadapter->init_para.int_mode;
+ pmadapter->gpio_pin = pmadapter->init_para.gpio_pin;
+
+#if defined(STA_SUPPORT)
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+#endif
+ pmadapter->cmd_sent = MFALSE;
+ pmadapter->data_sent = MTRUE;
+ pmadapter->mp_rd_bitmap = 0;
+ pmadapter->mp_wr_bitmap = 0;
+ pmadapter->curr_rd_port = 1;
+ pmadapter->curr_wr_port = 1;
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ pmadapter->mpa_tx.buf_len = 0;
+ pmadapter->mpa_tx.pkt_cnt = 0;
+ pmadapter->mpa_tx.start_port = 0;
+
+ if (!pmadapter->init_para.mpa_tx_cfg) {
+ pmadapter->mpa_tx.enabled = MFALSE;
+ } else if (pmadapter->init_para.mpa_tx_cfg == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->mpa_tx.enabled = MFALSE;
+ } else {
+ pmadapter->mpa_tx.enabled = MTRUE;
+ }
+ pmadapter->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ pmadapter->mpa_rx.buf_len = 0;
+ pmadapter->mpa_rx.pkt_cnt = 0;
+ pmadapter->mpa_rx.start_port = 0;
+
+ if (!pmadapter->init_para.mpa_rx_cfg) {
+ pmadapter->mpa_rx.enabled = MFALSE;
+ } else if (pmadapter->init_para.mpa_rx_cfg == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->mpa_rx.enabled = MFALSE;
+ } else {
+ pmadapter->mpa_rx.enabled = MTRUE;
+ }
+ pmadapter->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ pmadapter->cmd_resp_received = MFALSE;
+ pmadapter->event_received = MFALSE;
+ pmadapter->data_received = MFALSE;
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+
+ /* PnP and power profile */
+ pmadapter->surprise_removed = MFALSE;
+
+ /* Status variables */
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ if (!pmadapter->init_para.ps_mode) {
+ pmadapter->ps_mode = DEFAULT_PS_MODE;
+ } else if (pmadapter->init_para.ps_mode == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ } else {
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ }
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->need_to_wakeup = MFALSE;
+
+#ifdef STA_SUPPORT
+ /* Scan type */
+ pmadapter->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ /* Scan mode */
+ pmadapter->scan_mode = HostCmd_BSS_MODE_ANY;
+ /* Scan time */
+ pmadapter->specific_scan_time = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
+ pmadapter->active_scan_time = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+ pmadapter->passive_scan_time = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+
+ pmadapter->num_in_scan_table = 0;
+ memset(pmadapter, pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->ext_scan = 0;
+ pmadapter->scan_probes = DEFAULT_PROBES;
+
+ memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ pmadapter->radio_on = RADIO_ON;
+ pmadapter->multiple_dtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+ pmadapter->local_listen_interval = 0; /* default value in firmware
+ will be used */
+#endif /* STA_SUPPORT */
+
+ pmadapter->is_deep_sleep = MFALSE;
+ pmadapter->idle_time = DEEP_SLEEP_IDLE_TIME;
+ if (!pmadapter->init_para.auto_ds) {
+ pmadapter->init_auto_ds = DEFAULT_AUTO_DS_MODE;
+ } else if (pmadapter->init_para.auto_ds == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->init_auto_ds = MFALSE;
+ } else {
+ pmadapter->init_auto_ds = MTRUE;
+ }
+
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->delay_to_ps = DELAY_TO_PS_DEFAULT;
+ pmadapter->enhanced_ps_mode = PS_MODE_AUTO;
+
+ pmadapter->gen_null_pkt = MFALSE; /* Disable NULL Pkt generation-default */
+ pmadapter->pps_uapsd_mode = MFALSE; /* Disable pps/uapsd mode -default */
+
+ pmadapter->pm_wakeup_card_req = MFALSE;
+
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+
+ if (!pmadapter->init_para.max_tx_buf)
+ pmadapter->max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+ else
+ pmadapter->max_tx_buf_size = (t_u16) pmadapter->init_para.max_tx_buf;
+ pmadapter->tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+ pmadapter->curr_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+
+ pmadapter->is_hs_configured = MFALSE;
+ pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
+ pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
+ pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
+ pmadapter->hs_activated = MFALSE;
+
+ memset(pmadapter, pmadapter->event_body, 0, sizeof(pmadapter->event_body));
+ pmadapter->hw_dot_11n_dev_cap = 0;
+ pmadapter->hw_dev_mcs_support = 0;
+ pmadapter->usr_dot_11n_dev_cap_bg = 0;
+ pmadapter->usr_dot_11n_dev_cap_a = 0;
+ pmadapter->usr_dev_mcs_support = 0;
+#ifdef STA_SUPPORT
+ pmadapter->chan_bandwidth = 0;
+ pmadapter->adhoc_11n_enabled = MFALSE;
+#endif /* STA_SUPPORT */
+
+ /* Initialize 802.11d */
+ wlan_11d_init(pmadapter);
+
+ wlan_11h_init(pmadapter);
+
+ wlan_wmm_init(pmadapter);
+
+ if (pmadapter->psleep_cfm) {
+ pmadapter->psleep_cfm->buf_type = MLAN_BUF_TYPE_CMD;
+ pmadapter->psleep_cfm->data_len = sizeof(OPT_Confirm_Sleep);
+ memset(pmadapter, &sleep_cfm_buf->ps_cfm_sleep, 0,
+ sizeof(OPT_Confirm_Sleep));
+ sleep_cfm_buf->ps_cfm_sleep.command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ sleep_cfm_buf->ps_cfm_sleep.size =
+ wlan_cpu_to_le16(sizeof(OPT_Confirm_Sleep));
+ sleep_cfm_buf->ps_cfm_sleep.result = 0;
+ sleep_cfm_buf->ps_cfm_sleep.action = wlan_cpu_to_le16(SLEEP_CONFIRM);
+ sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl =
+ wlan_cpu_to_le16(RESP_NEEDED);
+ }
+ memset(pmadapter, &pmadapter->sleep_params, 0,
+ sizeof(pmadapter->sleep_params));
+ memset(pmadapter, &pmadapter->sleep_period, 0,
+ sizeof(pmadapter->sleep_period));
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->null_pkt_interval = 0;
+ pmadapter->fw_bands = 0;
+ pmadapter->config_bands = 0;
+ pmadapter->adhoc_start_band = 0;
+ pmadapter->pscan_channels = MNULL;
+ pmadapter->fw_release_number = 0;
+ pmadapter->fw_cap_info = 0;
+ memset(pmadapter, &pmadapter->upld_buf, 0, sizeof(pmadapter->upld_buf));
+ pmadapter->upld_len = 0;
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+ memset(pmadapter, &pmadapter->region_channel, 0,
+ sizeof(pmadapter->region_channel));
+ pmadapter->region_code = 0;
+ memcpy(pmadapter, pmadapter->country_code, MRVDRV_DEFAULT_COUNTRY_CODE,
+ COUNTRY_CODE_LEN);
+ pmadapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
+ pmadapter->adhoc_awake_period = 0;
+#ifdef STA_SUPPORT
+ memset(pmadapter, &pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
+ pmadapter->arp_filter_size = 0;
+#endif /* STA_SUPPORT */
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function intializes the lock variables and
+ * the list heads.
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_init_lock_list(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 i = 0;
+ t_u32 j = 0;
+
+ ENTER();
+
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pint_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->
+ moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pmain_proc_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pmlan_cmd_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &priv->rx_pkt_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->
+ moal_init_lock(pmadapter->pmoal_handle,
+ &priv->wmm.ra_list_spinlock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#ifdef STA_SUPPORT
+ if (pcb->
+ moal_init_lock(pmadapter->pmoal_handle,
+ &priv->curr_bcn_buf_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#endif
+ }
+ }
+
+ /* Initialize bypass_txq */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_free_q */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_pending_q */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize scan_pending_q */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[i].bssprio_head,
+ MTRUE, pmadapter->callbacks.moal_init_lock);
+ pmadapter->bssprio_tbl[i].bssprio_cur = MNULL;
+ }
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ for (j = 0; j < MAX_NUM_TID; ++j) {
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[j].ra_list, MTRUE,
+ priv->adapter->callbacks.moal_init_lock);
+ }
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *) pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, 0,
+ priv->wmm.ra_list_spinlock,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *) pmadapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
+ priv->wmm.ra_list_spinlock,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->sta_list, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ }
+ }
+
+ error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function releases the lock variables
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return None
+ *
+ */
+t_void
+wlan_free_lock_list(IN pmlan_adapter pmadapter)
+{
+ pmlan_private priv = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 i = 0;
+ t_s32 j = 0;
+
+ ENTER();
+
+ if (pmadapter->pmlan_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pmlan_lock);
+ if (pmadapter->pint_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ if (pmadapter->pmain_proc_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ if (pmadapter->pmlan_cmd_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ if (priv->rx_pkt_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, priv->rx_pkt_lock);
+ if (priv->wmm.ra_list_spinlock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+#ifdef STA_SUPPORT
+ if (priv->curr_bcn_buf_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->curr_bcn_buf_lock);
+#endif
+ }
+ }
+
+ /* Free lists */
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq,
+ pmadapter->callbacks.moal_free_lock);
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++)
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[i].bssprio_head,
+ pcb->moal_free_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.moal_free_lock);
+
+ for (j = 0; j < MAX_NUM_TID; ++j)
+ util_free_list_head((t_void *) priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[j].ra_list,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head((t_void *) priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head((t_void *) priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_scalar_free((t_void *) priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ priv->adapter->callbacks.moal_free_lock);
+ util_scalar_free((t_void *) priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ priv->adapter->callbacks.moal_free_lock);
+ }
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function intializes the timers
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_init_timer(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pcb->
+ moal_init_timer(pmadapter->pmoal_handle, &pmadapter->pmlan_cmd_timer,
+ wlan_cmd_timeout_func, pmadapter)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function releases the timers
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return None
+ *
+ */
+t_void
+wlan_free_timer(IN pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pmadapter->pmlan_cmd_timer)
+ pcb->moal_free_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_init_fw(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+
+ /* Initialize private structure */
+ if ((ret = wlan_init_priv(priv))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode != MTRUE) {
+#endif
+ /* Issue firmware initialize commands for first BSS, for other
+ interfaces it will be called after getting the last init command
+ response of previous interface */
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ ret = priv->ops.init_cmd(priv, MTRUE);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+#ifdef MFG_CMD_SUPPORT
+ }
+#endif
+
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ /* Send the first command in queue and return */
+ if (mlan_main_process(pmadapter) == MLAN_STATUS_FAILURE)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of adapter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_adapter(pmlan_adapter pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmadapter) {
+ PRINTM(MERROR, "The adapter is NULL\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_cancel_all_pending_cmd(pmadapter);
+ /* Free command buffer */
+ PRINTM(MINFO, "Free Command buffer\n");
+ wlan_free_cmd_buffer(pmadapter);
+
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+#ifdef STA_SUPPORT
+ PRINTM(MINFO, "Free ScanTable\n");
+ if (pmadapter->pscan_table) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->pscan_table);
+ pmadapter->pscan_table = MNULL;
+ }
+ if (pmadapter->bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter->bcn_buf);
+ pmadapter->bcn_buf = MNULL;
+ }
+#endif
+
+ wlan_11h_cleanup(pmadapter);
+
+ if (pmadapter->mp_regs_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->mp_regs_buf);
+ pmadapter->mp_regs_buf = MNULL;
+ pmadapter->mp_regs = MNULL;
+ }
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ wlan_free_sdio_mpa_buffers(pmadapter);
+#endif
+ wlan_free_mlan_buffer(pmadapter, pmadapter->psleep_cfm);
+ pmadapter->psleep_cfm = MNULL;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function frees the structure of priv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_priv(mlan_private * pmpriv)
+{
+ ENTER();
+ wlan_clean_txrx(pmpriv);
+ wlan_delete_bsspriotbl(pmpriv);
+
+#ifdef STA_SUPPORT
+ wlan_free_curr_bcn(pmpriv);
+#endif /* STA_SUPPORT */
+
+ wlan_delete_station_list(pmpriv);
+ LEAVE();
+}
+
+/**
+ * @brief The cmdresp handler calls this function for init_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization callback succeeded.
+ */
+mlan_status
+wlan_init_fw_complete(IN pmlan_adapter pmadapter)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Check if hardware is ready */
+ if (pmadapter->hw_status != WlanHardwareStatusReady)
+ status = MLAN_STATUS_FAILURE;
+
+ /* Invoke callback */
+ ret = pcb->moal_init_fw_complete(pmadapter->pmoal_handle, status);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The cmdresp handler calls this function for shutdown_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown callback succeeded.
+ */
+mlan_status
+wlan_shutdown_fw_complete(IN pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pmadapter->hw_status = WlanHardwareStatusNotReady;
+ /* Invoke callback */
+ ret = pcb->moal_shutdown_fw_complete(pmadapter->pmoal_handle, status);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_init.h b/drivers/net/wireless/sd8797/mlan/mlan_init.h
new file mode 100644
index 000000000000..4496741a3cfb
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_init.h
@@ -0,0 +1,88 @@
+/** @file mlan_init.h
+ *
+ * @brief This file defines the FW initialization data
+ * structures.
+ *
+ * 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
+******************************************************/
+
+#ifndef _MLAN_INIT_H_
+#define _MLAN_INIT_H_
+
+/** Tx buffer size for firmware download*/
+#define FW_DNLD_TX_BUF_SIZE 620
+/** Rx buffer size for firmware download*/
+#define FW_DNLD_RX_BUF_SIZE 2048
+/** Max firmware retry */
+#define MAX_FW_RETRY 3
+
+/** Firmware has last block */
+#define FW_HAS_LAST_BLOCK 0x00000004
+
+/** Firmware data transmit size */
+#define FW_DATA_XMIT_SIZE \
+ sizeof(FWHeader) + DataLength + sizeof(t_u32)
+
+/** FWHeader */
+typedef struct _FWHeader
+{
+ /** FW download command */
+ t_u32 dnld_cmd;
+ /** FW base address */
+ t_u32 base_addr;
+ /** FW data length */
+ t_u32 data_length;
+ /** FW CRC */
+ t_u32 crc;
+} FWHeader;
+
+/** FWData */
+typedef struct _FWData
+{
+ /** FW data header */
+ FWHeader fw_header;
+ /** FW data sequence number */
+ t_u32 seq_num;
+ /** FW data buffer */
+ t_u8 data[1];
+} FWData;
+
+/** FWSyncHeader */
+typedef struct _FWSyncHeader
+{
+ /** FW sync header command */
+ t_u32 cmd;
+ /** FW sync header sequence number */
+ t_u32 seq_num;
+} FWSyncHeader;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert sequence number and command fields of fwheader to correct endian format */
+#define endian_convert_syncfwheader(x) { \
+ (x)->cmd = wlan_le32_to_cpu((x)->cmd); \
+ (x)->seq_num = wlan_le32_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert sequence number and command fields of fwheader to correct endian format */
+#define endian_convert_syncfwheader(x)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+#endif /* _MLAN_INIT_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h b/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
new file mode 100644
index 000000000000..964de9197ffe
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
@@ -0,0 +1,2981 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ * 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/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** Enumeration for IOCTL request ID */
+enum _mlan_ioctl_req_id
+{
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL,
+ MLAN_OID_SCAN_SPECIFIC_SSID,
+ MLAN_OID_SCAN_USER_CONFIG,
+ MLAN_OID_SCAN_CONFIG,
+ MLAN_OID_SCAN_GET_CURRENT_BSS,
+ MLAN_OID_SCAN_CANCEL,
+ MLAN_OID_SCAN_TABLE_FLUSH,
+ MLAN_OID_SCAN_BGSCAN_CONFIG,
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START,
+ MLAN_OID_BSS_STOP,
+ MLAN_OID_BSS_MODE,
+ MLAN_OID_BSS_CHANNEL,
+ MLAN_OID_BSS_CHANNEL_LIST,
+ MLAN_OID_BSS_MAC_ADDR,
+ MLAN_OID_BSS_MULTICAST_LIST,
+ MLAN_OID_BSS_FIND_BSS,
+ MLAN_OID_IBSS_BCN_INTERVAL,
+ MLAN_OID_IBSS_ATIM_WINDOW,
+ MLAN_OID_IBSS_CHANNEL,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_BSS_CONFIG,
+ MLAN_OID_UAP_DEAUTH_STA,
+ MLAN_OID_UAP_BSS_RESET,
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ MLAN_OID_BSS_ROLE,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_WIFI_DIRECT_MODE,
+#endif
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL,
+ MLAN_OID_BAND_CFG,
+ MLAN_OID_ANT_CFG,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_REMAIN_CHAN_CFG,
+#endif
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT,
+#if defined(UAP_SUPPORT)
+ MLAN_OID_SNMP_MIB_DOT11D,
+ MLAN_OID_SNMP_MIB_DOT11H,
+#endif
+ MLAN_OID_SNMP_MIB_DTIM_PERIOD,
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS,
+ MLAN_OID_GET_SIGNAL,
+ MLAN_OID_GET_FW_INFO,
+ MLAN_OID_GET_VER_EXT,
+ MLAN_OID_GET_BSS_INFO,
+ MLAN_OID_GET_DEBUG_INFO,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_STA_LIST,
+#endif
+
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE,
+ MLAN_OID_SEC_CFG_WPA_ENABLED,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY,
+ MLAN_OID_SEC_CFG_PASSPHRASE,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED,
+ MLAN_OID_SEC_CFG_ESUPP_MODE,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED,
+ MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG,
+ MLAN_OID_GET_DATA_RATE,
+ MLAN_OID_SUPPORTED_RATES,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG,
+ MLAN_OID_POWER_CFG_EXT,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS,
+ MLAN_OID_PM_CFG_HS_CFG,
+ MLAN_OID_PM_CFG_INACTIVITY_TO,
+ MLAN_OID_PM_CFG_DEEP_SLEEP,
+ MLAN_OID_PM_CFG_SLEEP_PD,
+ MLAN_OID_PM_CFG_PS_CFG,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS,
+#ifdef UAP_SUPPORT
+ MLAN_OID_PM_CFG_PS_MODE,
+#endif /* UAP_SUPPORT */
+ MLAN_OID_PM_INFO,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE,
+ MLAN_OID_WMM_CFG_QOS,
+ MLAN_OID_WMM_CFG_ADDTS,
+ MLAN_OID_WMM_CFG_DELTS,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG,
+ MLAN_OID_WMM_CFG_QUEUE_STATS,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS,
+ MLAN_OID_WMM_CFG_TS_STATUS,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX,
+ MLAN_OID_11N_HTCAP_CFG,
+ MLAN_OID_11N_CFG_ADDBA_REJECT,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL,
+ MLAN_OID_11N_CFG_ADDBA_PARAM,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL,
+ MLAN_OID_11N_CFG_SUPPORTED_MCS_SET,
+ MLAN_OID_11N_CFG_TX_BF_CAP,
+ MLAN_OID_11N_CFG_TX_BF_CFG,
+ MLAN_OID_11N_CFG_STREAM_CFG,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+#ifdef STA_SUPPORT
+ MLAN_OID_11D_CFG_ENABLE,
+ MLAN_OID_11D_CLR_CHAN_TABLE,
+#endif /* STA_SUPPORT */
+ MLAN_OID_11D_DOMAIN_INFO,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW,
+ MLAN_OID_EEPROM_RD,
+ MLAN_OID_MEM_RW,
+
+ /* Multi-Radio Configuration Group */
+ MLAN_IOCTL_MFR_CFG = 0x00100000,
+
+ /* 802.11h Configuration Group */
+ MLAN_IOCTL_11H_CFG = 0x00110000,
+ MLAN_OID_11H_CHANNEL_CHECK,
+ MLAN_OID_11H_LOCAL_POWER_CONSTRAINT,
+#if defined(DFS_TESTING_SUPPORT)
+ MLAN_OID_11H_DFS_TESTING,
+#endif
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE,
+ MLAN_OID_MISC_REGION,
+ MLAN_OID_MISC_WARM_RESET,
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ MLAN_OID_MISC_SDIO_MPA_CTRL,
+#endif
+ MLAN_OID_MISC_HOST_CMD,
+ MLAN_OID_MISC_SYS_CLOCK,
+ MLAN_OID_MISC_SOFT_RESET,
+ MLAN_OID_MISC_WWS,
+ MLAN_OID_MISC_INIT_SHUTDOWN,
+ MLAN_OID_MISC_CUSTOM_IE,
+ MLAN_OID_MISC_TX_DATAPAUSE,
+ MLAN_OID_MISC_IP_ADDR,
+ MLAN_OID_MISC_MAC_CONTROL,
+ MLAN_OID_MISC_MEF_CFG,
+ MLAN_OID_MISC_CFP_CODE,
+ MLAN_OID_MISC_COUNTRY_CODE,
+ MLAN_OID_MISC_THERMAL,
+ MLAN_OID_MISC_RX_MGMT_IND,
+ MLAN_OID_MISC_SUBSCRIBE_EVENT,
+#ifdef DEBUG_LEVEL1
+ MLAN_OID_MISC_DRVDBG,
+#endif
+ MLAN_OID_MISC_OTP_USER_DATA,
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum _mlan_act_ioctl
+{
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL
+};
+
+/** Enumeration for generic enable/disable */
+enum _mlan_act_generic
+{
+ MLAN_ACT_DISABLE = 0,
+ MLAN_ACT_ENABLE = 1
+};
+
+/** Enumeration for scan mode */
+enum _mlan_scan_mode
+{
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum _mlan_scan_type
+{
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE
+};
+
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 4
+
+/** Default number of probes to send on each channel */
+#define DEFAULT_PROBES 4
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value in microseconds from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid
+{
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows after the fixed_field_length
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /*
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ /* t_u8 bss_info_buffer[0]; */
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params
+{
+ /** Scan channel time for specific scan in milliseconds */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan in milliseconds */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan in milliseconds */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan
+{
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req
+{
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp
+{
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+ /* Age in seconds */
+ t_u32 age_in_secs;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg
+{
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Extended Scan */
+ t_u32 ext_scan;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union
+ {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum _mlan_bss_mode
+{
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+
+/** max Wmm AC queues */
+#define MAX_AC_QUEUES 4
+
+/** Maximum atim window in milliseconds */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list
+{
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Max channel */
+#define MLAN_MAX_CHANNEL 165
+
+/** Maximum number of channels in table */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq
+{
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list
+{
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/** mlan_ssid_bssid data structure for MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS */
+typedef struct _mlan_ssid_bssid
+{
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+ /** index in BSSID list, start from 1 */
+ t_u32 idx;
+} mlan_ssid_bssid;
+
+#ifdef UAP_SUPPORT
+/** Maximum packet forward control value */
+#define MAX_PKT_FWD_CTRL 15
+/** Maximum BEACON period */
+#define MAX_BEACON_PERIOD 4000
+/** Minimum BEACON period */
+#define MIN_BEACON_PERIOD 50
+/** Maximum DTIM period */
+#define MAX_DTIM_PERIOD 100
+/** Minimum DTIM period */
+#define MIN_DTIM_PERIOD 1
+/** Maximum TX Power Limit */
+#define MAX_TX_POWER 20
+/** Minimum TX Power Limit */
+#define MIN_TX_POWER 0
+/** MAX station count */
+#define MAX_STA_COUNT 10
+/** Maximum RTS threshold */
+#define MAX_RTS_THRESHOLD 2347
+/** Maximum fragmentation threshold */
+#define MAX_FRAG_THRESHOLD 2346
+/** Minimum fragmentation threshold */
+#define MIN_FRAG_THRESHOLD 256
+/** data rate 54 M */
+#define DATA_RATE_54M 108
+/** antenna A */
+#define ANTENNA_MODE_A 0
+/** antenna B */
+#define ANTENNA_MODE_B 1
+/** transmit antenna */
+#define TX_ANTENNA 1
+/** receive antenna */
+#define RX_ANTENNA 0
+/** Maximum stage out time */
+#define MAX_STAGE_OUT_TIME 864000
+/** Minimum stage out time */
+#define MIN_STAGE_OUT_TIME 300
+/** Maximum Retry Limit */
+#define MAX_RETRY_LIMIT 14
+
+/** Maximum group key timer in seconds */
+#define MAX_GRP_TIMER 86400
+
+/** Maximum value of 4 byte configuration */
+#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */
+
+/** Band config ACS mode */
+#define BAND_CONFIG_ACS_MODE 0x40
+/** Band config manual */
+#define BAND_CONFIG_MANUAL 0x00
+
+/** Maximum data rates */
+#define MAX_DATA_RATES 14
+
+/** auto data rate */
+#define DATA_RATE_AUTO 0
+
+/**filter mode: disable */
+#define MAC_FILTER_MODE_DISABLE 0
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_ALLOW_MAC 1
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_BLOCK_MAC 2
+/** Maximum mac filter num */
+#define MAX_MAC_FILTER_NUM 16
+
+/* Bitmap for protocol to use */
+/** No security */
+#define PROTOCOL_NO_SECURITY 0x01
+/** Static WEP */
+#define PROTOCOL_STATIC_WEP 0x02
+/** WPA */
+#define PROTOCOL_WPA 0x08
+/** WPA2 */
+#define PROTOCOL_WPA2 0x20
+/** WP2 Mixed */
+#define PROTOCOL_WPA2_MIXED 0x28
+/** EAP */
+#define PROTOCOL_EAP 0x40
+/** WAPI */
+#define PROTOCOL_WAPI 0x80
+
+/** Key_mgmt_psk */
+#define KEY_MGMT_NONE 0x04
+/** Key_mgmt_none */
+#define KEY_MGMT_PSK 0x02
+/** Key_mgmt_eap */
+#define KEY_MGMT_EAP 0x01
+
+/** TKIP */
+#define CIPHER_TKIP 0x04
+/** AES CCMP */
+#define CIPHER_AES_CCMP 0x08
+
+/** Valid cipher bitmap */
+#define VALID_CIPHER_BITMAP 0x0c
+
+/** Channel List Entry */
+typedef struct _channel_list
+{
+ /** Channel Number */
+ t_u8 chan_number;
+ /** Band Config */
+ t_u8 band_config_type;
+} scan_chan_list;
+
+/** mac_filter data structure */
+typedef struct _mac_filter
+{
+ /** mac filter mode */
+ t_u16 filter_mode;
+ /** mac adress count */
+ t_u16 mac_count;
+ /** mac address list */
+ mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM];
+} mac_filter;
+
+/** wpa parameter */
+typedef struct _wpa_param
+{
+ /** Pairwise cipher WPA */
+ t_u8 pairwise_cipher_wpa;
+ /** Pairwise cipher WPA2 */
+ t_u8 pairwise_cipher_wpa2;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** RSN replay protection */
+ t_u8 rsn_protection;
+ /** passphrase length */
+ t_u32 length;
+ /** passphrase */
+ t_u8 passphrase[64];
+ /**group key rekey time in seconds */
+ t_u32 gk_rekey_time;
+} wpa_param;
+
+/** wep key */
+typedef struct _wep_key
+{
+ /** key index 0-3 */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** length */
+ t_u16 length;
+ /** key data */
+ t_u8 key[26];
+} wep_key;
+
+/** wep param */
+typedef struct _wep_param
+{
+ /** key 0 */
+ wep_key key0;
+ /** key 1 */
+ wep_key key1;
+ /** key 2 */
+ wep_key key2;
+ /** key 3 */
+ wep_key key3;
+} wep_param;
+
+/** Data structure of WMM QoS information */
+typedef struct _wmm_qos_info_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_qos_info_t, *pwmm_qos_info_t;
+
+/** Data structure of WMM ECW */
+typedef struct _wmm_ecw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_ecw_t, *pwmm_ecw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _wmm_aci_aifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _wmm_ac_parameters_t
+{
+ wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */
+ wmm_ecw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} wmm_ac_parameters_t, *pwmm_ac_parameters_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _wmm_parameter_t
+{
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+} wmm_parameter_t, *pwmm_parameter_t;
+
+/** mlan_bss_param
+ * Note: For each entry you must enter an invalid value
+ * in the MOAL function woal_set_sys_config_invalid_data().
+ * Otherwise for a valid data an unwanted TLV will be
+ * added to that command.
+ */
+typedef struct _mlan_uap_bss_param
+{
+ /** AP mac addr */
+ mlan_802_11_mac_addr mac_addr;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Broadcast ssid control */
+ t_u8 bcast_ssid_ctl;
+ /** Radio control: on/off */
+ t_u8 radio_ctl;
+ /** dtim period */
+ t_u8 dtim_period;
+ /** beacon period */
+ t_u16 beacon_period;
+ /** rates */
+ t_u8 rates[MAX_DATA_RATES];
+ /** Tx data rate */
+ t_u16 tx_data_rate;
+ /** multicast/broadcast data rate */
+ t_u16 mcbc_data_rate;
+ /** Tx power level in dBm */
+ t_u8 tx_power_level;
+ /** Tx antenna */
+ t_u8 tx_antenna;
+ /** Rx antenna */
+ t_u8 rx_antenna;
+ /** packet forward control */
+ t_u8 pkt_forward_ctl;
+ /** max station count */
+ t_u16 max_sta_count;
+ /** mac filter */
+ mac_filter filter;
+ /** station ageout timer in unit of 100ms */
+ t_u32 sta_ageout_timer;
+ /** PS station ageout timer in unit of 100ms */
+ t_u32 ps_sta_ageout_timer;
+ /** RTS threshold */
+ t_u16 rts_threshold;
+ /** fragmentation threshold */
+ t_u16 frag_threshold;
+ /** retry_limit */
+ t_u16 retry_limit;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+ /** preamble type */
+ t_u8 preamble_type;
+ /** band cfg */
+ t_u8 band_cfg;
+ /** channel */
+ t_u8 channel;
+ /** auth mode */
+ t_u16 auth_mode;
+ /** encryption protocol */
+ t_u16 protocol;
+ /** key managment type */
+ t_u16 key_mgmt;
+ /** wep param */
+ wep_param wep_cfg;
+ /** wpa param */
+ wpa_param wpa_cfg;
+ /** Mgmt IE passthru mask */
+ t_u32 mgmt_ie_passthru_mask;
+ /*
+ * 11n HT Cap HTCap_t ht_cap
+ */
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Enable 2040 Coex */
+ t_u8 enable_2040coex;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+ /** BSS status */
+ t_u16 bss_status;
+#ifdef WIFI_DIRECT_SUPPORT
+ /* pre shared key */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+#endif /* WIFI_DIRECT_SUPPORT */
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+ /** Wmm parameters */
+ wmm_parameter_t wmm_para;
+} mlan_uap_bss_param;
+
+/** mlan_deauth_param */
+typedef struct _mlan_deauth_param
+{
+ /** STA mac addr */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** deauth reason */
+ t_u16 reason_code;
+} mlan_deauth_param;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** mode: disable wifi direct */
+#define WIFI_DIRECT_MODE_DISABLE 0
+/** mode: listen */
+#define WIFI_DIRECT_MODE_LISTEN 1
+/** mode: GO */
+#define WIFI_DIRECT_MODE_GO 2
+/** mode: client */
+#define WIFI_DIRECT_MODE_CLIENT 3
+/** mode: find */
+#define WIFI_DIRECT_MODE_FIND 4
+/** mode: stop find */
+#define WIFI_DIRECT_MODE_STOP_FIND 5
+#endif
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union
+ {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+#ifdef UAP_SUPPORT
+ /** BSS param for AP mode */
+ mlan_uap_bss_param bss_config;
+ /** deauth param for MLAN_OID_UAP_DEAUTH_STA */
+ mlan_deauth_param deauth_param;
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ /** BSS role */
+ t_u8 bss_role;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ t_u16 wfd_mode;
+#endif
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for band */
+enum _mlan_band_def
+{
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+};
+
+/** NO secondary channel */
+#define NO_SEC_CHANNEL 0
+/** secondary channel is above primary channel */
+#define SEC_CHANNEL_ABOVE 1
+/** secondary channel is below primary channel */
+#define SEC_CHANNEL_BELOW 3
+/** Channel bandwidth */
+#define CHANNEL_BW_20MHZ 0
+#define CHANNEL_BW_40MHZ_ABOVE 1
+#define CHANNEL_BW_40MHZ_BELOW 3
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg
+{
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+ /** Ad-hoc channel bandwidth */
+ t_u32 sec_chan_offset;
+ /** fw supported band */
+ t_u32 fw_bands;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg
+{
+ /** Tx antenna mode */
+ t_u32 tx_antenna;
+ /** Rx antenna mode */
+ t_u32 rx_antenna;
+} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */
+typedef struct _mlan_ds_remain_chan
+{
+ /** remove flag */
+ t_u16 remove;
+ /** status */
+ t_u8 status;
+ /** Band cfg */
+ t_u8 bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} mlan_ds_remain_chan, *pmlan_ds_remain_chan;
+#endif
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union
+ {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg ant_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ t_u32 antenna;
+#ifdef WIFI_DIRECT_SUPPORT
+ /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */
+ mlan_ds_remain_chan remain_chan;
+#endif
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union
+ {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+#if defined(UAP_SUPPORT)
+ /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
+ t_u32 oid_value;
+#endif
+ /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */
+ t_u32 dtim_period;
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum _mlan_adhoc_status
+{
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED, ADHOC_STARTING
+};
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats
+{
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_uap_stats
+{
+ /** tkip mic failures */
+ t_u32 tkip_mic_failures;
+ /** ccmp decrypt errors */
+ t_u32 ccmp_decrypt_errors;
+ /** wep undecryptable count */
+ t_u32 wep_undecryptable_count;
+ /** wep icv error count */
+ t_u32 wep_icv_error_count;
+ /** decrypt failure count */
+ t_u32 decrypt_failure_count;
+ /** dot11 multicast tx count */
+ t_u32 mcast_tx_count;
+ /** dot11 failed count */
+ t_u32 failed_count;
+ /** dot11 retry count */
+ t_u32 retry_count;
+ /** dot11 multi retry count */
+ t_u32 multi_retry_count;
+ /** dot11 frame duplicate count */
+ t_u32 frame_dup_count;
+ /** dot11 rts success count */
+ t_u32 rts_success_count;
+ /** dot11 rts failure count */
+ t_u32 rts_failure_count;
+ /** dot11 ack failure count */
+ t_u32 ack_failure_count;
+ /** dot11 rx ragment count */
+ t_u32 rx_fragment_count;
+ /** dot11 mcast rx frame count */
+ t_u32 mcast_rx_frame_count;
+ /** dot11 fcs error count */
+ t_u32 fcs_error_count;
+ /** dot11 tx frame count */
+ t_u32 tx_frame_count;
+ /** dot11 rsna tkip cm invoked */
+ t_u32 rsna_tkip_cm_invoked;
+ /** dot11 rsna 4way handshake failures */
+ t_u32 rsna_4way_hshk_failures;
+} mlan_ds_uap_stats, *pmlan_ds_uap_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal
+{
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info
+{
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** fw supported band */
+ t_u8 fw_bands;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext
+{
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info
+{
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Band */
+ t_u8 bss_band;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level in dBm */
+ t_u32 max_power_level;
+ /** Min power level in dBm */
+ t_u32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+#ifdef STA_SUPPORT
+ /** Capability Info */
+ t_u16 capability_info;
+ /** Beacon Interval */
+ t_u16 beacon_interval;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Association Id */
+ t_u16 assoc_id;
+ /** AP/Peer supported rates */
+ t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES];
+#endif /* STA_SUPPORT */
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** amsdu flag */
+ t_u8 amsdu;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** amsdu flag */
+ t_u8 amsdu;
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info
+{
+ /* WMM AC_BK count */
+ t_u32 wmm_ac_bk;
+ /* WMM AC_BE count */
+ t_u32 wmm_ac_be;
+ /* WMM AC_VI count */
+ t_u32 wmm_ac_vi;
+ /* WMM AC_VO count */
+ t_u32 wmm_ac_vo;
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Corresponds to curr_tx_buf_size member of mlan_adapter*/
+ t_u32 curr_tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+#ifdef STA_SUPPORT
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+#endif /** STA_SUPPORT */
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+ /** Corresponds to pps_uapsd_mode member of mlan_adapter */
+ t_u16 pps_uapsd_mode;
+ /** Corresponds to sleep_period.period member of mlan_adapter */
+ t_u16 sleep_pd;
+ /** Corresponds to wmm_qosinfo member of mlan_private */
+ t_u8 qos_cfg;
+ /** Corresponds to tx_lock_flag member of mlan_adapter */
+ t_u8 tx_lock_flag;
+ /** Corresponds to port_open member of mlan_private */
+ t_u8 port_open;
+ /** Corresponds to scan_processing member of mlan_adapter */
+ t_u32 scan_processing;
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+ /** pendig tx pkts */
+ t_u32 tx_pkts_queued;
+#ifdef UAP_SUPPORT
+ /** pending bridge pkts */
+ t_u16 num_bridge_pkts;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+} mlan_debug_info, *pmlan_debug_info;
+
+#ifdef UAP_SUPPORT
+/** Maximum number of clients supported by AP */
+#define MAX_NUM_CLIENTS MAX_STA_COUNT
+
+/** station info */
+typedef struct _sta_info
+{
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mfg status */
+ t_u8 power_mfg_status;
+ /** RSSI */
+ t_s8 rssi;
+} sta_info;
+
+/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */
+typedef struct _mlan_ds_sta_list
+{
+ /** station count */
+ t_u16 sta_count;
+ /** station list */
+ sta_info info[MAX_NUM_CLIENTS];
+} mlan_ds_sta_list, *pmlan_ds_sta_list;
+#endif
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info
+{
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union
+ {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ mlan_debug_info debug_info;
+#ifdef UAP_SUPPORT
+ /** UAP Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_uap_stats ustats;
+ /** UAP station list for MLAN_OID_UAP_STA_LIST */
+ mlan_ds_sta_list sta_list;
+#endif
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum _mlan_auth_mode
+{
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/** Enumeration for encryption mode */
+enum _mlan_encryption_mode
+{
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+};
+
+/** Enumeration for PSK */
+enum _mlan_psk_type
+{
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+};
+
+/** The bit to indicate the key is for unicast */
+#define MLAN_KEY_INDEX_UNICAST 0x40000000
+/** The key index to indicate default key */
+#define MLAN_KEY_INDEX_DEFAULT 0x000000ff
+/** Maximum key length */
+// #define MLAN_MAX_KEY_LENGTH 32
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** PMK length */
+#define MLAN_PMK_HEXSTR_LENGTH 64
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+/** packet number size */
+#define PN_SIZE 16
+/** max seq size of wpa/wpa2 key */
+#define SEQ_MAX_SIZE 8
+
+/** key flag for tx_seq */
+#define KEY_FLAG_TX_SEQ_VALID 0x00000001
+/** key flag for rx_seq */
+#define KEY_FLAG_RX_SEQ_VALID 0x00000002
+/** key flag for group key */
+#define KEY_FLAG_GROUP_KEY 0x00000004
+/** key flag for tx and rx */
+#define KEY_FLAG_SET_TX_KEY 0x00000008
+/** key flag for remove key */
+#define KEY_FLAG_REMOVE_KEY 0x80000000
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key
+{
+ /** Key disabled, all other fields will be ignore when this flag set to MTRUE */
+ t_u32 key_disable;
+ /** key removed flag, when this flag is set to MTRUE, only key_index will be check */
+ t_u32 key_remove;
+ /** Key index, used as current tx key index when is_current_wep_key is set to MTRUE */
+ t_u32 key_index;
+ /** Current Tx key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+ /** key flags */
+ t_u32 key_flags;
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t
+{
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t
+{
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_KEY_LENGTH];
+} mlan_pmk_t;
+
+/** Embedded supplicant RSN type: No RSN */
+#define RSN_TYPE_NO_RSN MBIT(0)
+/** Embedded supplicant RSN type: WPA */
+#define RSN_TYPE_WPA MBIT(3)
+/** Embedded supplicant RSN type: WPA-NONE */
+#define RSN_TYPE_WPANONE MBIT(4)
+/** Embedded supplicant RSN type: WPA2 */
+#define RSN_TYPE_WPA2 MBIT(5)
+/** Embedded supplicant RSN type: RFU */
+#define RSN_TYPE_VALID_BITS (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2)
+
+/** Embedded supplicant cipher type: TKIP */
+#define EMBED_CIPHER_TKIP MBIT(2)
+/** Embedded supplicant cipher type: AES */
+#define EMBED_CIPHER_AES MBIT(3)
+/** Embedded supplicant cipher type: RFU */
+#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES)
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase
+{
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union
+ {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode
+{
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union
+ {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */
+ t_u32 port_ctrl_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for MLAN_OID_SEC_CFG_EWPA_ENABLED */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for rate type */
+enum _mlan_rate_type
+{
+ MLAN_RATE_INDEX,
+ MLAN_RATE_VALUE
+};
+
+/** Enumeration for rate format */
+enum _mlan_rate_format
+{
+ MLAN_RATE_FORMAT_LG = 0,
+ MLAN_RATE_FORMAT_HT,
+ MLAN_RATE_FORMAT_AUTO = 0xFF,
+};
+/** Max bitmap rates size */
+#define MAX_BITMAP_RATES_SIZE 10
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t
+{
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type. 0: index; 1: valude */
+ t_u32 rate_type;
+ /** Rate/MCS index or rate value if fixed rate */
+ t_u32 rate;
+ /** Rate Bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+} mlan_rate_cfg_t;
+
+/** HT channel bandwidth */
+typedef enum _mlan_ht_bw
+{
+ MLAN_HT_BW20,
+ MLAN_HT_BW40,
+} mlan_ht_bw;
+
+/** HT guard interval */
+typedef enum _mlan_ht_gi
+{
+ MLAN_HT_LGI,
+ MLAN_HT_SGI,
+} mlan_ht_gi;
+
+/** Band and BSS mode */
+typedef struct _mlan_band_data_rate
+{
+ /** Band configuration */
+ t_u8 config_bands;
+ /** BSS mode (Infra or IBSS) */
+ t_u8 bss_mode;
+} mlan_band_data_rate;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate
+{
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+
+ /** Tx channel bandwidth */
+ t_u32 tx_ht_bw;
+ /** Tx guard interval */
+ t_u32 tx_ht_gi;
+ /** Rx channel bandwidth */
+ t_u32 rx_ht_bw;
+ /** Rx guard interval */
+ t_u32 rx_ht_gi;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union
+ {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ /** Band/BSS mode for getting supported rates */
+ mlan_band_data_rate rate_band_cfg;
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t
+{
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level in dBm */
+ t_u32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+
+/** The HT BW40 bit in Tx rate index */
+#define TX_RATE_HT_BW40_BIT MBIT(7)
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext
+{
+ /** Length of power_data */
+ t_u32 len;
+ /** Buffer of power configuration data */
+ t_u32 power_data[MAX_POWER_TABLE_SIZE];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union
+ {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Host sleep config condition: broadcast data */
+#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0)
+/** Host sleep config condition: unicast data */
+#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1)
+/** Host sleep config condition: mac event */
+#define HOST_SLEEP_COND_MAC_EVENT MBIT(2)
+/** Host sleep config condition: multicast data */
+#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3)
+
+/** Host sleep config conditions: Default */
+#define HOST_SLEEP_DEF_COND (HOST_SLEEP_COND_BROADCAST_DATA | HOST_SLEEP_COND_UNICAST_DATA | HOST_SLEEP_COND_MAC_EVENT)
+/** Host sleep config GPIO : Default */
+#define HOST_SLEEP_DEF_GPIO 0xff
+/** Host sleep config gap : Default */
+#define HOST_SLEEP_DEF_GAP 200
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg
+{
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: broadcast data
+ * Bit1: unicast data
+ * Bit2: mac event
+ * Bit3: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u32 gpio;
+ /** Gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */
+ t_u32 gap;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time in milliseconds for auto deep sleep */
+#define DEEP_SLEEP_IDLE_TIME 100
+
+typedef struct _mlan_ds_auto_ds
+{
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time in milliseconds */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to for MLAN_OID_PM_CFG_INACTIVITY_TO */
+typedef struct _mlan_ds_inactivity_to
+{
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period in milliseconds */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period in milliseconds */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Local listen interval disable */
+#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1)
+/** Minimum listen interval */
+#define MRVDRV_MIN_LISTEN_INTERVAL 0
+
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Match listen interval to closest DTIM */
+#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd
+
+/** Minimum adhoc awake period */
+#define MIN_ADHOC_AWAKE_PD 0
+/** Maximum adhoc awake period */
+#define MAX_ADHOC_AWAKE_PD 31
+/** Special adhoc awake period */
+#define SPECIAL_ADHOC_AWAKE_PD 255
+
+/** Minimum beacon miss timeout in milliseconds */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout in milliseconds */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS in milliseconds */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS in milliseconds */
+#define MAX_DELAY_TO_PS 65535
+/** Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+/** Default delay to PS in milliseconds */
+#define DELAY_TO_PS_DEFAULT 1000
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg
+{
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Adhoc awake period */
+ t_u32 adhoc_awake_period;
+ /** Beacon miss timeout in milliseconds */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS in milliseconds */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params
+{
+ /** Error */
+ t_u32 error;
+ /** Offset in microseconds */
+ t_u32 offset;
+ /** Stable time in microseconds */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** sleep_param */
+typedef struct _ps_sleep_param
+{
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** minimum sleep period (micro second) */
+ t_u32 min_sleep;
+ /** maximum sleep period (micro second) */
+ t_u32 max_sleep;
+} ps_sleep_param;
+
+/** inactivity sleep_param */
+typedef struct _inact_sleep_param
+{
+ /** inactivity timeout (micro second) */
+ t_u32 inactivity_to;
+ /** miniumu awake period (micro second) */
+ t_u32 min_awake;
+ /** maximum awake period (micro second) */
+ t_u32 max_awake;
+} inact_sleep_param;
+
+/** flag for ps mode */
+#define PS_FLAG_PS_MODE 1
+/** flag for sleep param */
+#define PS_FLAG_SLEEP_PARAM 2
+/** flag for inactivity sleep param */
+#define PS_FLAG_INACT_SLEEP_PARAM 4
+
+/** Disable power mode */
+#define PS_MODE_DISABLE 0
+/** Enable periodic dtim ps */
+#define PS_MODE_PERIODIC_DTIM 1
+/** Enable inactivity ps */
+#define PS_MODE_INACTIVITY 2
+
+/** mlan_ds_ps_mgmt */
+typedef struct _mlan_ds_ps_mgmt
+{
+ /** flags for valid field */
+ t_u16 flags;
+ /** power mode */
+ t_u16 ps_mode;
+ /** sleep param */
+ ps_sleep_param sleep_param;
+ /** inactivity sleep param */
+ inact_sleep_param inact_param;
+} mlan_ds_ps_mgmt;
+
+/** mlan_ds_ps_info */
+typedef struct _mlan_ds_ps_info
+{
+ /** suspend allowed flag */
+ t_u32 is_suspend_allowed;
+} mlan_ds_ps_info;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union
+ {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+ mlan_ds_sleep_params sleep_params;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */
+ mlan_ds_ps_mgmt ps_mgmt;
+ /** power info for MLAN_OID_PM_INFO */
+ mlan_ds_ps_info ps_info;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */
+ + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** User Priority */
+ t_u8 user_priority;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+/** Type definition of mlan_ds_wmm_queue_stats for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+/** Type definition of mlan_ds_wmm_queue_status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts
+{
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the ADDTS + buffering for any extra IEs */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts
+{
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+typedef struct _mlan_ds_wmm_queue_config
+{
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union
+ {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum _mlan_wps_status
+{
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union
+ {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+/** Supported stream modes */
+#define HT_STREAM_MODE_1X1 0x11
+#define HT_STREAM_MODE_2X2 0x22
+
+/* Both 2.4G and 5G band selected */
+#define BAND_SELECT_BOTH 0
+/* Band 2.4G selected */
+#define BAND_SELECT_BG 1
+/* Band 5G selected */
+#define BAND_SELECT_A 2
+
+/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */
+typedef struct _mlan_ds_11n_htcap_cfg
+{
+ /** HT Capability information */
+ t_u32 htcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg;
+
+/** Type definition of mlan_ds_11n_addba_param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+typedef struct _mlan_ds_11n_addba_param
+{
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg
+{
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+ /** Band selection */
+ t_u32 misc_cfg;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** BF Global Configuration */
+#define BF_GLOBAL_CONFIGURATION 0x00
+/** Performs NDP sounding for PEER specified */
+#define TRIGGER_SOUNDING_FOR_PEER 0x01
+/** TX BF interval for channel sounding */
+#define SET_GET_BF_PERIODICITY 0x02
+/** Tell FW not to perform any sounding for peer */
+#define TX_BF_FOR_PEER_ENBL 0x03
+/** TX BF SNR threshold for peer */
+#define SET_SNR_THR_PEER 0x04
+
+/* Maximum number of peer MAC and status/SNR tuples */
+#define MAX_PEER_MAC_TUPLES 10
+
+/** Any new subcommand structure should be declare here */
+
+/** bf global cfg args */
+typedef struct _mlan_bf_global_cfg_args
+{
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval in milliseconds */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} mlan_bf_global_cfg_args;
+
+/** trigger sounding args */
+typedef struct _mlan_trigger_sound_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} mlan_trigger_sound_args;
+
+/** bf periodicity args */
+typedef struct _mlan_bf_periodicity_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval in milliseconds */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} mlan_bf_periodicity_args;
+
+/** tx bf peer args */
+typedef struct _mlan_tx_bf_peer_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} mlan_tx_bf_peer_args;
+
+/** SNR threshold args */
+typedef struct _mlan_snr_thr_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR for peer */
+ t_u8 snr;
+} mlan_snr_thr_args;
+
+/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */
+typedef struct _mlan_ds_11n_tx_bf_cfg
+{
+ /** BF Action */
+ t_u16 bf_action;
+ /** Action */
+ t_u16 action;
+ /** Number of peers */
+ t_u32 no_of_peers;
+ union
+ {
+ mlan_bf_global_cfg_args bf_global_cfg;
+ mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES];
+ mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES];
+ mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES];
+ mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES];
+ } body;
+} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl
+{
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+typedef struct _mlan_ds_11n_aggr_prio_tbl
+{
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union
+ {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ mlan_ds_11n_htcap_cfg htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_FIELD];
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Transmit Beamforming configuration */
+ mlan_ds_11n_tx_bf_cfg tx_bf;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+#ifdef STA_SUPPORT
+/** Data structure for subband set */
+typedef struct _mlan_ds_subband_set_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} mlan_ds_subband_set_t;
+
+/** Domain regulatory information */
+typedef struct _mlan_ds_11d_domain_info
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} mlan_ds_11d_domain_info;
+#endif
+
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union
+ {
+#ifdef STA_SUPPORT
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+ /** Domain info for MLAN_OID_11D_DOMAIN_INFO */
+ mlan_ds_11d_domain_info domain_info;
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ /** tlv data for MLAN_OID_11D_DOMAIN_INFO */
+ t_u8 domain_tlv[MAX_IE_SIZE];
+#endif /* UAP_SUPPORT */
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for register type */
+enum _mlan_reg_type
+{
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_CAU = 5,
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw
+{
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom
+{
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw
+{
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union
+ {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** Multi-Radio Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------*/
+/** 802.11h Configuration Group */
+/*-----------------------------------------------------------------*/
+#if defined(DFS_TESTING_SUPPORT)
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */
+typedef struct _mlan_ds_11h_dfs_testing
+{
+ /** User-configured CAC period in milliseconds, 0 to use default */
+ t_u16 usr_cac_period_msec;
+ /** User-configured NOP period in seconds, 0 to use default */
+ t_u16 usr_nop_period_sec;
+ /** User-configured skip channel change, 0 to disable */
+ t_u8 usr_no_chan_change;
+ /** User-configured fixed channel to change to, 0 to use random channel */
+ t_u8 usr_fixed_new_chan;
+} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing;
+#endif
+
+/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */
+typedef struct _mlan_ds_11h_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ union
+ {
+ /** Local power constraint for MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */
+ t_s8 usr_local_power_constraint;
+#if defined(DFS_TESTING_SUPPORT)
+ /** User-configuation for MLAN_OID_11H_DFS_TESTING */
+ mlan_ds_11h_dfs_testing dfs_testing;
+#endif
+ } param;
+} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER 2048
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum _mlan_ie_type
+{
+ MLAN_IE_TYPE_GEN_IE = 0,
+#ifdef STA_SUPPORT
+ MLAN_IE_TYPE_ARP_FILTER,
+#endif /* STA_SUPPORT */
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie
+{
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl for MLAN_OID_MISC_SDIO_MPA_CTRL */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl
+{
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd
+{
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MLAN_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock
+{
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Enumeration for function init/shutdown */
+enum _mlan_func_cmd
+{
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_tx_datapause for MLAN_OID_MISC_TX_DATAPAUSE */
+typedef struct _mlan_ds_misc_tx_datapause
+{
+ /** Tx data pause flag */
+ t_u16 tx_pause;
+ /** Max number of Tx buffers for all PS clients */
+ t_u16 tx_buf_cnt;
+} mlan_ds_misc_tx_datapause;
+
+/** IP address length */
+#define IPADDR_LEN (16)
+/** Max number of ip */
+#define MAX_IPADDR (4)
+/** IP address type - IPv4*/
+#define IPADDR_TYPE_IPV4 (1)
+/** IP operation remove */
+#define MLAN_IPADDR_OP_IP_REMOVE (0)
+/** IP operation ARP filter */
+#define MLAN_IPADDR_OP_ARP_FILTER MBIT(0)
+/** IP operation ARP response */
+#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1)
+
+/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */
+typedef struct _mlan_ds_misc_ipaddr_cfg
+{
+ /** Operation code */
+ t_u32 op_code;
+ /** IP address type */
+ t_u32 ip_addr_type;
+ /** Number of IP */
+ t_u32 ip_addr_num;
+ /** IP address */
+ t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN];
+} mlan_ds_misc_ipaddr_cfg;
+
+/* MEF configuration disable */
+#define MEF_CFG_DISABLE 0
+/* MEF configuration Rx filter enable */
+#define MEF_CFG_RX_FILTER_ENABLE 1
+/* MEF configuration auto ARP response */
+#define MEF_CFG_AUTO_ARP_RESP 2
+/* MEF configuration host command */
+#define MEF_CFG_HOSTCMD 0xFFFF
+
+/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */
+typedef struct _mlan_ds_misc_mef_cfg
+{
+ /** Sub-ID for operation */
+ t_u32 sub_id;
+ /** Parameter according to sub-ID */
+ union
+ {
+ /** MEF command buffer for MEF_CFG_HOSTCMD */
+ mlan_ds_misc_cmd cmd_buf;
+ } param;
+} mlan_ds_misc_mef_cfg;
+
+/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_misc_cfp_code
+{
+ /** CFP table code for 2.4GHz */
+ t_u32 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u32 cfp_code_a;
+} mlan_ds_misc_cfp_code;
+
+/** Type definition of mlan_ds_misc_country_code for MLAN_OID_MISC_COUNTRY_CODE */
+typedef struct _mlan_ds_misc_country_code
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+} mlan_ds_misc_country_code;
+
+/** BITMAP for subscribe event rssi low */
+#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
+/** BITMAP for subscribe event snr low */
+#define SUBSCRIBE_EVT_SNR_LOW MBIT(1)
+/** BITMAP for subscribe event max fail */
+#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2)
+/** BITMAP for subscribe event beacon missed */
+#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3)
+/** BITMAP for subscribe event rssi high */
+#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4)
+/** BITMAP for subscribe event snr high */
+#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5)
+/** BITMAP for subscribe event data rssi low */
+#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6)
+/** BITMAP for subscribe event data snr low */
+#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7)
+/** BITMAP for subscribe event data rssi high */
+#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8)
+/** BITMAP for subscribe event data snr high */
+#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9)
+/** BITMAP for subscribe event link quality */
+#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
+/** BITMAP for subscribe event pre_beacon_lost */
+#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+/** default PRE_BEACON_MISS_COUNT */
+#define DEFAULT_PRE_BEACON_MISS 30
+
+/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_subscribe_evt
+{
+ /** bitmap for subscribe event */
+ t_u16 evt_bitmap;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_snr_freq;
+ /** Failure count threshold */
+ t_u8 failure_count;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 failure_count_freq;
+ /** num of missed beacons */
+ t_u8 beacon_miss;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 beacon_miss_freq;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_snr_freq;
+ /* Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /* Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+ /* Number of pre missed beacons */
+ t_u8 pre_beacon_miss;
+} mlan_ds_subscribe_evt;
+
+/** Max OTP user data length */
+#define MAX_OTP_USER_DATA_LEN 252
+
+/** Type definition of mlan_ds_misc_otp_user_data for MLAN_OID_MISC_OTP_USER_DATA */
+typedef struct _mlan_ds_misc_otp_user_data
+{
+ /** Reserved */
+ t_u16 reserved;
+ /** OTP user data length */
+ t_u16 user_data_length;
+ /** User data buffer */
+ t_u8 user_data[MAX_OTP_USER_DATA_LEN];
+} mlan_ds_misc_otp_user_data;
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union
+ {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */
+ mlan_ds_misc_custom_ie cust_ie;
+ /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */
+ mlan_ds_misc_tx_datapause tx_datapause;
+ /** IP address configuration */
+ mlan_ds_misc_ipaddr_cfg ipaddr_cfg;
+ /** MAC control for MLAN_OID_MISC_MAC_CONTROL */
+ t_u32 mac_ctrl;
+ /** MEF configuration for MLAN_OID_MISC_MEF_CFG */
+ mlan_ds_misc_mef_cfg mef_cfg;
+ /** CFP code for MLAN_OID_MISC_CFP_CODE */
+ mlan_ds_misc_cfp_code cfp_code;
+ /** Country code for MLAN_OID_MISC_COUNTRY_CODE */
+ mlan_ds_misc_country_code country_code;
+ /** Thermal reading for MLAN_OID_MISC_THERMAL */
+ t_u32 thermal;
+ /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
+ t_u32 mgmt_subtype_mask;
+ /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */
+ mlan_ds_subscribe_evt subscribe_event;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ mlan_ds_misc_otp_user_data otp_user_data;
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_join.c b/drivers/net/wireless/sd8797/mlan/mlan_join.c
new file mode 100644
index 000000000000..1399ae8b3c16
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_join.c
@@ -0,0 +1,1853 @@
+/** @file mlan_join.c
+ *
+ * @brief Functions implementing wlan infrastructure and adhoc join routines
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending adhoc start, adhoc join, and association commands
+ * to the firmware.
+ *
+ * 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/30/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"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Constants
+********************************************************/
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Append a generic IE as a pass through TLV to a TLV buffer.
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a pass through TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_generic_ie(mlan_private * priv, t_u8 ** ppbuffer)
+{
+ int ret_len = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a generic ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->gen_ie_buf_len) {
+ PRINTM(MINFO, "append generic IE %d to %p\n", priv->gen_ie_buf_len,
+ *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = wlan_cpu_to_le16(priv->gen_ie_buf_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 generic IE buffer to the output buffer, advance pointer */
+ memcpy(priv->adapter, *ppbuffer, priv->gen_ie_buf,
+ priv->gen_ie_buf_len);
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += priv->gen_ie_buf_len;
+ ret_len += priv->gen_ie_buf_len;
+
+ /* Reset the generic IE buffer */
+ priv->gen_ie_buf_len = 0;
+ }
+
+ /* return the length appended to the buffer */
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Append TSF tracking info from the scan table for the target AP
+ *
+ * This function is called from the network join command prep. routine.
+ * The TSF table TSF sent to the firmware contains two TSF values:
+ * - the TSF of the target AP from its previous beacon/probe response
+ * - the TSF timestamp of our local MAC at the time we observed the
+ * beacon/probe response.
+ *
+ * The firmware uses the timestamp values to set an initial TSF value
+ * in the MAC for the new association after a reassociation attempt.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ppbuffer A pointer to command buffer pointer
+ * @param pbss_desc A pointer to the BSS Descriptor from the scan table of
+ * the AP we are trying to join
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_tsf_tlv(mlan_private * pmriv, t_u8 ** ppbuffer,
+ BSSDescriptor_t * pbss_desc)
+{
+ MrvlIEtypes_TsfTimestamp_t tsf_tlv;
+ t_u64 tsf_val;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(pmriv->adapter, &tsf_tlv, 0x00, sizeof(MrvlIEtypes_TsfTimestamp_t));
+
+ tsf_tlv.header.type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+ tsf_tlv.header.len = wlan_cpu_to_le16(2 * sizeof(tsf_val));
+
+ memcpy(pmriv->adapter, *ppbuffer, &tsf_tlv, sizeof(tsf_tlv.header));
+ *ppbuffer += sizeof(tsf_tlv.header);
+
+ /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received */
+ tsf_val = wlan_cpu_to_le64(pbss_desc->network_tsf);
+ memcpy(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ memcpy(pmriv->adapter, &tsf_val, pbss_desc->time_stamp, sizeof(tsf_val));
+
+ PRINTM(MINFO, "ASSOC: TSF offset calc: %016llx - %016llx\n",
+ tsf_val, pbss_desc->network_tsf);
+
+ memcpy(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ LEAVE();
+ return (sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)));
+}
+
+/**
+ * @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates needs to be taken
+ * care of, either before or after calling this function
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rate1 the buffer which keeps input and output
+ * @param rate1_size the size of rate1 buffer
+ * @param rate2 the buffer which keeps rate2
+ * @param rate2_size the size of rate2 buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_common_rates(IN mlan_private * pmpriv,
+ IN t_u8 * rate1,
+ IN t_u32 rate1_size, IN t_u8 * rate2, IN t_u32 rate2_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ t_u8 *ptr = rate1;
+ t_u8 *tmp = MNULL;
+ t_u32 i, j;
+
+ ENTER();
+
+ ret =
+ pcb->moal_malloc(pmpriv->adapter->pmoal_handle, rate1_size,
+ MLAN_MEM_DEF, &tmp);
+ if (ret != MLAN_STATUS_SUCCESS || !tmp) {
+ PRINTM(MERROR, "Failed to allocate buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memcpy(pmpriv->adapter, tmp, rate1, rate1_size);
+ memset(pmpriv->adapter, rate1, 0, rate1_size);
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ for (j = 0; tmp[j] && j < rate1_size; j++) {
+ /* Check common rate, excluding the bit for basic rate */
+ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+ *rate1++ = tmp[j];
+ break;
+ }
+ }
+ }
+
+ HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
+ HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
+ HEXDUMP("Common Rates", ptr, rate1 - ptr);
+ PRINTM(MINFO, "Tx DataRate is set to 0x%X\n", pmpriv->data_rate);
+
+ if (!pmpriv->is_data_rate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == pmpriv->data_rate) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ ptr++;
+ }
+ PRINTM(MMSG, "Previously set fixed data rate %#x is not "
+ "compatible with the network\n", pmpriv->data_rate);
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (tmp)
+ pcb->moal_mfree(pmpriv->adapter->pmoal_handle, tmp);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create the intersection of the rates supported by a target BSS and
+ * our pmadapter settings for use in an assoc/join command.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc BSS Descriptor whose rates are used in the setup
+ * @param pout_rates Output: Octet array of rates common between the BSS
+ * and the pmadapter supported rates settings
+ * @param pout_rates_size Output: Number of rates/octets set in pout_rates
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_setup_rates_from_bssdesc(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc,
+ OUT t_u8 * pout_rates,
+ OUT t_u32 * pout_rates_size)
+{
+ t_u8 card_rates[WLAN_SUPPORTED_RATES];
+ t_u32 card_rates_size = 0;
+ ENTER();
+ /* Copy AP supported rates */
+ memcpy(pmpriv->adapter, pout_rates, pbss_desc->supported_rates,
+ WLAN_SUPPORTED_RATES);
+ /* Get the STA supported rates */
+ card_rates_size = wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ pmpriv->config_bands,
+ card_rates);
+ /* Get the common rates between AP and STA supported rates */
+ if (wlan_get_common_rates(pmpriv, pout_rates, WLAN_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ *pout_rates_size = 0;
+ PRINTM(MERROR, "wlan_get_common_rates failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *pout_rates_size =
+ MIN(wlan_strlen((char *) pout_rates), WLAN_SUPPORTED_RATES);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Update the scan entry TSF timestamps to reflect a new association
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pnew_bss_desc A pointer to the newly associated AP's scan table entry
+ *
+ * @return N/A
+ */
+static t_void
+wlan_update_tsf_timestamps(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pnew_bss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 table_idx;
+ t_u64 new_tsf_base;
+ t_s64 tsf_delta;
+
+ ENTER();
+
+ memcpy(pmpriv->adapter, &new_tsf_base, pnew_bss_desc->time_stamp,
+ sizeof(new_tsf_base));
+
+ tsf_delta = new_tsf_base - pnew_bss_desc->network_tsf;
+
+ PRINTM(MINFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
+ pnew_bss_desc->network_tsf, new_tsf_base);
+
+ for (table_idx = 0; table_idx < pmadapter->num_in_scan_table; table_idx++) {
+ pmadapter->pscan_table[table_idx].network_tsf += tsf_delta;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Append a wapi IE
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a wapi TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppBuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_wapi_ie(mlan_private * priv, t_u8 ** ppBuffer)
+{
+ int retLen = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppBuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppBuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a wapi ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->wapi_ie_len) {
+ PRINTM(MCMND, "append wapi ie %d to %p\n", priv->wapi_ie_len,
+ *ppBuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header.len = wlan_cpu_to_le16(priv->wapi_ie_len);
+ memcpy(priv->adapter, *ppBuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppBuffer += sizeof(ie_header);
+ retLen += sizeof(ie_header);
+
+ /* Copy the wapi IE buffer to the output buffer, advance pointer */
+ memcpy(priv->adapter, *ppBuffer, priv->wapi_ie, priv->wapi_ie_len);
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppBuffer += priv->wapi_ie_len;
+ retLen += priv->wapi_ie_len;
+
+ }
+ /* return the length appended to the buffer */
+ LEAVE();
+ return retLen;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prepares command of association.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of BSSDescriptor_t from the
+ * scan table to assoc
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_ASSOCIATE *passo = &cmd->params.associate;
+ BSSDescriptor_t *pbss_desc;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv;
+ MrvlIEtypes_PhyParamSet_t *pphy_tlv;
+ MrvlIEtypes_SsParamSet_t *pss_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ MrvlIEtypes_AuthType_t *pauth_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ t_u16 tmp_cap;
+ t_u8 *pos;
+
+ ENTER();
+
+ pbss_desc = (BSSDescriptor_t *) pdata_buf;
+ pos = (t_u8 *) passo;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ memcpy(pmadapter, passo->peer_sta_addr,
+ pbss_desc->mac_address, sizeof(passo->peer_sta_addr));
+ pos += sizeof(passo->peer_sta_addr);
+
+ /* Set the listen interval */
+ passo->listen_interval = wlan_cpu_to_le16(pmpriv->listen_interval);
+ /* Set the beacon period */
+ passo->beacon_period = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ pos += sizeof(passo->cap_info);
+ pos += sizeof(passo->listen_interval);
+ pos += sizeof(passo->beacon_period);
+ pos += sizeof(passo->dtim_period);
+
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) pos;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len = (t_u16) pbss_desc->ssid.ssid_len;
+ memcpy(pmadapter, pssid_tlv->ssid, pbss_desc->ssid.ssid,
+ pssid_tlv->header.len);
+ pos += sizeof(pssid_tlv->header) + pssid_tlv->header.len;
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+
+ pphy_tlv = (MrvlIEtypes_PhyParamSet_t *) pos;
+ pphy_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
+ pphy_tlv->header.len = sizeof(pphy_tlv->fh_ds.ds_param_set);
+ memcpy(pmadapter, &pphy_tlv->fh_ds.ds_param_set,
+ &pbss_desc->phy_param_set.ds_param_set.current_chan,
+ sizeof(pphy_tlv->fh_ds.ds_param_set));
+ pos += sizeof(pphy_tlv->header) + pphy_tlv->header.len;
+ pphy_tlv->header.len = wlan_cpu_to_le16(pphy_tlv->header.len);
+
+ pss_tlv = (MrvlIEtypes_SsParamSet_t *) pos;
+ pss_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CF);
+ pss_tlv->header.len = sizeof(pss_tlv->cf_ibss.cf_param_set);
+ pos += sizeof(pss_tlv->header) + pss_tlv->header.len;
+ pss_tlv->header.len = wlan_cpu_to_le16(pss_tlv->header.len);
+
+ /* Get the common rates supported between the driver and the BSS Desc */
+ if (wlan_setup_rates_from_bssdesc(pmpriv, pbss_desc, rates, &rates_size)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the data rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(pmadapter, &pmpriv->curr_bss_params.data_rates, rates, rates_size);
+
+ /* Setup the Rates TLV in the association command */
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *) pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16) rates_size);
+ memcpy(pmadapter, prates_tlv->rates, rates, rates_size);
+ pos += sizeof(prates_tlv->header) + rates_size;
+ PRINTM(MINFO, "ASSOC_CMD: Rates size = %d\n", rates_size);
+
+ /* Add the Authentication type to be used for Auth frames if needed */
+ if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO) {
+ pauth_tlv = (MrvlIEtypes_AuthType_t *) pos;
+ pauth_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ pauth_tlv->header.len = sizeof(pauth_tlv->auth_type);
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pauth_tlv->auth_type =
+ wlan_cpu_to_le16((t_u16) pmpriv->sec_info.authentication_mode);
+ else
+ pauth_tlv->auth_type = wlan_cpu_to_le16(MLAN_AUTH_MODE_OPEN);
+ pos += sizeof(pauth_tlv->header) + pauth_tlv->header.len;
+ pauth_tlv->header.len = wlan_cpu_to_le16(pauth_tlv->header.len);
+ }
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)
+ && (pbss_desc->bss_band & pmpriv->config_bands)
+ && !(ISSUPP_11NENABLED(pmadapter->fw_cap_info)
+ && (!pbss_desc->disable_11n)
+ && (pmpriv->config_bands & BAND_GN
+ || pmpriv->config_bands & BAND_AN)
+ && (pbss_desc->pht_cap)
+ )
+ ) {
+ /* Append a channel TLV for the channel the attempted AP was found on */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "Assoc: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type =
+ wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ PRINTM(MINFO, "Assoc: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+ if (!pmpriv->wps.session_enable) {
+ if ((pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE
+ or
+ RSN_IE
+ */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie)).vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie)).data[0])
+ , prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmadapter->fw_cap_info)
+ && (!pbss_desc->disable_11n)
+ && (pmpriv->config_bands & BAND_GN || pmpriv->config_bands & BAND_AN))
+ wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+
+ wlan_wmm_process_association_req(pmpriv, &pos, &pbss_desc->wmm_ie,
+ pbss_desc->pht_cap);
+ if (pmpriv->sec_info.wapi_enabled && pmpriv->wapi_ie_len) {
+ wlan_cmd_append_wapi_ie(pmpriv, &pos);
+ }
+
+ wlan_cmd_append_generic_ie(pmpriv, &pos);
+
+ wlan_cmd_append_tsf_tlv(pmpriv, &pos, pbss_desc);
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, (t_u8) pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv, pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so adhoc/infra 11h
+ * behavior can be properly triggered. pos modified if data is appended
+ */
+ wlan_11h_process_join(pmpriv, &pos, &passo->cap_info,
+ (t_u8) pbss_desc->bss_band,
+ pbss_desc->phy_param_set.ds_param_set.current_chan,
+ &pbss_desc->wlan_11h_bss_info);
+
+ cmd->size = wlan_cpu_to_le16((t_u16) (pos - (t_u8 *) passo) + S_DS_GEN);
+
+ /* Set the Capability info at last */
+ memcpy(pmadapter, &tmp_cap, &pbss_desc->cap_info, sizeof(passo->cap_info));
+
+ if (pmpriv->config_bands == BAND_B) {
+ SHORT_SLOT_TIME_DISABLED(tmp_cap);
+ }
+
+ tmp_cap &= CAPINFO_MASK;
+ PRINTM(MINFO, "ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy(pmadapter, &passo->cap_info, &tmp_cap, sizeof(passo->cap_info));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Association firmware command response handler
+ *
+ * The response buffer for the association command has the following
+ * memory layout.
+ *
+ * For cases where an association response was not received (indicated
+ * by the CapInfo and AId field):
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info/Error Return(t_u16): |
+ * | 0xFFFF(-1): Internal error for association |
+ * | 0xFFFE(-2): Authentication unhandled message |
+ * | 0xFFFD(-3): Authentication refused |
+ * | 0xFFFC(-4): Timeout waiting for AP response |
+ * | 0xFFFB(-5): Internal error for authentication |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): |
+ * | If cap_info is -1: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status code |
+ * | is 6 if associate response parameter invlaid, |
+ * | 1 otherwise. |
+ * | |
+ * | If cap_info is -2: |
+ * | An authentication frame was received but was |
+ * | not handled by the firmware. IEEE Status code |
+ * | for the failure is returned. |
+ * | |
+ * | If cap_info is -3: |
+ * | An authentication frame was received and the |
+ * | status_code is the IEEE Status reported in the |
+ * | response. |
+ * | |
+ * | If cap_info is -4: |
+ * | (1) Association response timeout |
+ * | (2) Authentication response timeout |
+ * | |
+ * | If cap_info is -5: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status code |
+ * | is 6 if authentication parameter invlaid, |
+ * | 1 otherwise. |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): 0xFFFF |
+ * .------------------------------------------------------------.
+ *
+ *
+ * For cases where an association response was received, the IEEE
+ * standard association response frame is returned:
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info(t_u16): IEEE Capability |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): IEEE Status Code |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): IEEE Association ID |
+ * .------------------------------------------------------------.
+ * | IEEE IEs(variable): Any received IEs comprising the |
+ * | remaining portion of a received |
+ * | association response frame. |
+ * .------------------------------------------------------------.
+ *
+ * For simplistic handling, the status_code field can be used to determine
+ * an association success (0) or failure (non-zero).
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ IEEEtypes_AssocRsp_t *passoc_rsp;
+ BSSDescriptor_t *pbss_desc;
+ t_u8 enable_data = MTRUE;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ passoc_rsp = (IEEEtypes_AssocRsp_t *) & resp->params;
+ passoc_rsp->status_code = wlan_le16_to_cpu(passoc_rsp->status_code);
+
+ HEXDUMP("ASSOC_RESP:", (t_u8 *) & resp->params, (resp->size - S_DS_GEN));
+
+ pmpriv->assoc_rsp_size = MIN(resp->size - S_DS_GEN,
+ sizeof(pmpriv->assoc_rsp_buf));
+
+ memcpy(pmpriv->adapter, pmpriv->assoc_rsp_buf, &resp->params,
+ pmpriv->assoc_rsp_size);
+
+ if (passoc_rsp->status_code) {
+ pmpriv->adapter->dbg.num_cmd_assoc_failure++;
+ PRINTM(MERROR, "ASSOC_RESP: Association Failed, "
+ "status code = %d, error = 0x%x, a_id = 0x%x\n",
+ wlan_le16_to_cpu(passoc_rsp->status_code),
+ wlan_le16_to_cpu(*(t_u16 *) & passoc_rsp->capability),
+ wlan_le16_to_cpu(passoc_rsp->a_id));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ pmpriv->adapter->tx_lock_flag = MFALSE;
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+
+ /* Set the attempted BSSID Index to current */
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ PRINTM(MINFO, "ASSOC_RESP: %s\n", pbss_desc->ssid.ssid);
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t));
+
+ /* Update curr_bss_params */
+ pmpriv->curr_bss_params.bss_descriptor.channel
+ = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ pmpriv->curr_bss_params.band = (t_u8) pbss_desc->bss_band;
+
+ /*
+ * Adjust the timestamps in the scan table to be relative to the newly
+ * associated AP's TSF
+ */
+ wlan_update_tsf_timestamps(pmpriv, pbss_desc);
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE)
+ pmpriv->curr_bss_params.wmm_enabled = MTRUE;
+ else
+ pmpriv->curr_bss_params.wmm_enabled = MFALSE;
+
+ if ((pmpriv->wmm_required
+ || (pbss_desc->pht_cap &&
+ (pbss_desc->pht_cap->ieee_hdr.element_id == HT_CAPABILITY))
+ ) && pmpriv->curr_bss_params.wmm_enabled)
+ pmpriv->wmm_enabled = MTRUE;
+ else
+ pmpriv->wmm_enabled = MFALSE;
+
+ pmpriv->curr_bss_params.wmm_uapsd_enabled = MFALSE;
+
+ if (pmpriv->wmm_enabled == MTRUE)
+ pmpriv->curr_bss_params.wmm_uapsd_enabled
+ = pbss_desc->wmm_ie.qos_info.qos_uapsd;
+
+ PRINTM(MINFO, "ASSOC_RESP: curr_pkt_filter is 0x%x\n",
+ pmpriv->curr_pkt_filter);
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)
+ pmpriv->wpa_is_gtk_set = MFALSE;
+
+ if (pmpriv->wmm_enabled)
+ /* Don't re-enable carrier until we get the WMM_GET_STATUS event */
+ enable_data = MFALSE;
+ else
+ /* Since WMM is not enabled, setup the queues with the defaults */
+ wlan_wmm_setup_queues(pmpriv);
+
+ if (enable_data) {
+ PRINTM(MINFO, "Post association, re-enabling data flow\n");
+ }
+
+ /* Reset SNR/NF/RSSI values */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+ pmpriv->rxpd_rate = 0;
+ pmpriv->rxpd_htinfo = 0;
+ if (pbss_desc->pht_cap) {
+ if (GETHT_MAXAMSDU(pbss_desc->pht_cap->ht_cap.ht_cap_info))
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ }
+
+ wlan_save_curr_bcn(pmpriv);
+
+ pmpriv->adapter->dbg.num_cmd_assoc_success++;
+
+ PRINTM(MINFO, "ASSOC_RESP: Associated\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pmpriv->adapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Add the ra_list here for infra mode as there will be only 1 ra always */
+ wlan_ralist_add(pmpriv, pmpriv->curr_bss_params.bss_descriptor.mac_address);
+
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+
+ /* Send OBSS scan param to the application if available */
+ wlan_2040_coex_event(pmpriv);
+
+ if (!pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && !pmpriv->sec_info.ewpa_enabled && !pmpriv->sec_info.wapi_enabled) {
+ /* We are in Open/WEP mode, open port immediately */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ pmpriv->port_open = MTRUE;
+ PRINTM(MINFO, "ASSOC_RESP: port_status = OPEN\n");
+ }
+ }
+
+ if (pmpriv->sec_info.wpa_enabled
+ || pmpriv->sec_info.wpa2_enabled
+ || pmpriv->sec_info.ewpa_enabled || pmpriv->sec_info.wapi_enabled)
+ pmpriv->scan_block = MTRUE;
+
+ done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (passoc_rsp->status_code)
+ pioctl_req->status_code =
+ wlan_le16_to_cpu(passoc_rsp->status_code);
+ else
+ pioctl_req->status_code = MLAN_ERROR_CMD_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_start.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_start(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_START *padhoc_start = &cmd->params.adhoc_start;
+ BSSDescriptor_t *pbss_desc;
+ t_u32 cmd_append_size = 0;
+ t_u32 i;
+ t_u16 tmp_cap;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIETypes_HTInfo_t *pht_info;
+ /* wpa ie for WPA_NONE AES */
+ const t_u8 wpa_ie[24] = { 0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
+ 0x00, 0x50, 0xf2, 0x04, 0x01, 0x00, 0x00, 0x50,
+ 0xf2, 0x00, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x00
+ };
+ t_s32 append_size_11h = 0;
+ t_u8 *pos = (t_u8 *) padhoc_start + sizeof(HostCmd_DS_802_11_AD_HOC_START);
+
+ ENTER();
+
+ if (!pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. HostCmd_DS_802_11_AD_HOC_START command
+ * 2. pbss_desc
+ * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
+ * probe delay, and Cap info.
+ * Firmware will fill up beacon period, Basic rates
+ * and operational rates.
+ */
+
+ memset(pmadapter, padhoc_start->ssid, 0, MLAN_MAX_SSID_LENGTH);
+
+ memcpy(pmadapter, padhoc_start->ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid_len));
+
+ PRINTM(MINFO, "ADHOC_S_CMD: SSID = %s\n", padhoc_start->ssid);
+
+ memset(pmadapter, pbss_desc->ssid.ssid, 0, MLAN_MAX_SSID_LENGTH);
+ memcpy(pmadapter, pbss_desc->ssid.ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid_len));
+
+ pbss_desc->ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, ((mlan_802_11_ssid *) pdata_buf)->ssid_len);
+
+ /* Set the BSS mode */
+ padhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
+ pbss_desc->bss_mode = MLAN_BSS_MODE_IBSS;
+ padhoc_start->beacon_period = wlan_cpu_to_le16(pmpriv->beacon_period);
+ pbss_desc->beacon_period = pmpriv->beacon_period;
+
+ /* Set Physical param set */
+/** Parameter IE Id */
+#define DS_PARA_IE_ID 3
+/** Parameter IE length */
+#define DS_PARA_IE_LEN 1
+
+ padhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
+ padhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
+
+ if (!wlan_get_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band, (t_u16) pmpriv->adhoc_channel,
+ pmadapter->region_channel)) {
+
+ chan_freq_power_t *cfp;
+ cfp =
+ wlan_get_cfp_by_band_and_channel(pmadapter,
+ pmadapter->adhoc_start_band,
+ FIRST_VALID_CHANNEL,
+ pmadapter->region_channel);
+ if (cfp)
+ pmpriv->adhoc_channel = (t_u8) cfp->channel;
+ }
+
+ MASSERT(pmpriv->adhoc_channel);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
+ pmpriv->adhoc_channel);
+
+ pmpriv->curr_bss_params.bss_descriptor.channel = pmpriv->adhoc_channel;
+ pmpriv->curr_bss_params.band = pmadapter->adhoc_start_band;
+
+ pbss_desc->channel = pmpriv->adhoc_channel;
+ padhoc_start->phy_param_set.ds_param_set.current_chan =
+ pmpriv->adhoc_channel;
+
+ memcpy(pmadapter, &pbss_desc->phy_param_set,
+ &padhoc_start->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t));
+
+ pbss_desc->network_type_use = Wlan802_11DS;
+
+ /* Set IBSS param set */
+/** IBSS parameter IE Id */
+#define IBSS_PARA_IE_ID 6
+/** IBSS parameter IE length */
+#define IBSS_PARA_IE_LEN 2
+
+ padhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
+ padhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
+ padhoc_start->ss_param_set.ibss_param_set.atim_window
+ = wlan_cpu_to_le16(pmpriv->atim_window);
+ pbss_desc->atim_window = pmpriv->atim_window;
+ memcpy(pmadapter, &pbss_desc->ss_param_set,
+ &padhoc_start->ss_param_set, sizeof(IEEEtypes_SsParamSet_t));
+
+ /* Set Capability info */
+ padhoc_start->cap.ess = 0;
+ padhoc_start->cap.ibss = 1;
+ pbss_desc->cap_info.ibss = 1;
+
+ /* Set up privacy in pbss_desc */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ || pmpriv->adhoc_aes_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+/** Ad-Hoc capability privacy on */
+#define AD_HOC_CAP_PRIVACY_ON 1
+ PRINTM(MINFO, "ADHOC_S_CMD: wep_status set, Privacy to WEP\n");
+ pbss_desc->privacy = Wlan802_11PrivFilter8021xWEP;
+ padhoc_start->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ } else {
+ PRINTM(MWARN, "ADHOC_S_CMD: wep_status NOT set, Setting "
+ "Privacy to ACCEPT ALL\n");
+ pbss_desc->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ memset(pmadapter, padhoc_start->DataRate, 0,
+ sizeof(padhoc_start->DataRate));
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ pmadapter->adhoc_start_band,
+ padhoc_start->DataRate);
+ if ((pmadapter->adhoc_start_band & BAND_G) &&
+ (pmpriv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+
+ if (ret) {
+ PRINTM(MERROR, "ADHOC_S_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(padhoc_start->DataRate) && padhoc_start->DataRate[i];
+ i++);
+
+ pmpriv->curr_bss_params.num_of_rates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS rate structure */
+ memcpy(pmadapter, &pmpriv->curr_bss_params.data_rates,
+ &padhoc_start->DataRate, pmpriv->curr_bss_params.num_of_rates);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n",
+ padhoc_start->DataRate[0], padhoc_start->DataRate[1],
+ padhoc_start->DataRate[2], padhoc_start->DataRate[3]);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (t_u8) pmpriv->curr_bss_params.bss_descriptor.channel;
+
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type
+ = wlan_band_to_radio_type(pmpriv->curr_bss_params.band);
+ if (pmadapter->adhoc_start_band & BAND_GN
+ || pmadapter->adhoc_start_band & BAND_AN) {
+ if (pmadapter->chan_bandwidth == CHANNEL_BW_40MHZ_ABOVE) {
+ pchan_tlv->chan_scan_param[0].radio_type |=
+ SECOND_CHANNEL_ABOVE;
+ pchan_tlv->chan_scan_param[0].radio_type |= CHAN_BW_40MHZ << 2;
+ } else if (pmadapter->chan_bandwidth == CHANNEL_BW_40MHZ_BELOW) {
+ pchan_tlv->chan_scan_param[0].radio_type |=
+ SECOND_CHANNEL_BELOW;
+ pchan_tlv->chan_scan_param[0].radio_type |= CHAN_BW_40MHZ << 2;
+ }
+ }
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, pmpriv->curr_bss_params.band)) {
+ PRINTM(MERROR, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h start API to add any 11h flags/elements as TLV parameters
+ */
+ append_size_11h = wlan_11h_process_start(pmpriv, &pos, &padhoc_start->cap,
+ pmpriv->adhoc_channel,
+ &pbss_desc->wlan_11h_bss_info);
+ if (append_size_11h >= 0)
+ cmd_append_size += append_size_11h;
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmpriv->sec_info.ewpa_enabled) {
+ memcpy(pmadapter, pmpriv->wpa_ie, wpa_ie, sizeof(wpa_ie));
+ pmpriv->wpa_ie_len = sizeof(wpa_ie);
+ }
+
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE or
+ RSN_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "ADHOC_S_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+
+ if (pmadapter->adhoc_11n_enabled == MTRUE) {
+ {
+ pht_cap = (MrvlIETypes_HTCap_t *) pos;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->curr_bss_params.band);
+ HEXDUMP("ADHOC_START: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ pos += sizeof(MrvlIETypes_HTCap_t);
+ cmd_append_size += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+ {
+ pht_info = (MrvlIETypes_HTInfo_t *) pos;
+ memset(pmadapter, pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
+ pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
+ pht_info->header.len = sizeof(HTInfo_t);
+ pht_info->ht_info.pri_chan =
+ (t_u8) pmpriv->curr_bss_params.bss_descriptor.channel;
+ if (pmadapter->chan_bandwidth) {
+ pht_info->ht_info.field2 = pmadapter->chan_bandwidth;
+ SET_CHANWIDTH40(pht_info->ht_info.field2);
+ }
+ pht_info->ht_info.field3 = NON_GREENFIELD_STAS;
+ pht_info->ht_info.basic_mcs_set[0] = 0xff;
+ HEXDUMP("ADHOC_START: HT_INFORMATION IE", (t_u8 *) pht_info,
+ sizeof(MrvlIETypes_HTInfo_t));
+ pos += sizeof(MrvlIETypes_HTInfo_t);
+ cmd_append_size += sizeof(MrvlIETypes_HTInfo_t);
+ pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
+ }
+ }
+
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(HostCmd_DS_802_11_AD_HOC_START)
+ + S_DS_GEN + cmd_append_size));
+
+ memcpy(pmadapter, &tmp_cap, &padhoc_start->cap, sizeof(t_u16));
+
+ if (pmadapter->adhoc_start_band == BAND_B) {
+ SHORT_SLOT_TIME_DISABLED(tmp_cap);
+ } else {
+ SHORT_SLOT_TIME_ENABLED(tmp_cap);
+ }
+
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy(pmadapter, &padhoc_start->cap, &tmp_cap, sizeof(t_u16));
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_join.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void cast of BSSDescriptor_t from the
+ * scan table to join
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_join(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_JOIN *padhoc_join = &cmd->params.adhoc_join;
+ BSSDescriptor_t *pbss_desc = (BSSDescriptor_t *) pdata_buf;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ t_u32 cmd_append_size = 0;
+ t_u16 tmp_cap;
+ t_u32 i, rates_size = 0;
+ t_u16 curr_pkt_filter;
+ t_u8 *pos = (t_u8 *) padhoc_join + sizeof(HostCmd_DS_802_11_AD_HOC_JOIN);
+
+ ENTER();
+
+/** Use G protection */
+#define USE_G_PROTECTION 0x02
+ if (pbss_desc->erp_flags & USE_G_PROTECTION) {
+ curr_pkt_filter =
+ pmpriv->curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &curr_pkt_filter);
+ if (ret) {
+ PRINTM(MERROR, "ADHOC_J_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+ padhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
+
+ padhoc_join->bss_descriptor.beacon_period
+ = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.bssid,
+ &pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.ssid,
+ &pbss_desc->ssid.ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, pbss_desc->ssid.ssid_len));
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.phy_param_set,
+ &pbss_desc->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t));
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.ss_param_set,
+ &pbss_desc->ss_param_set, sizeof(IEEEtypes_SsParamSet_t));
+
+ memcpy(pmadapter, &tmp_cap, &pbss_desc->cap_info,
+ sizeof(IEEEtypes_CapInfo_t));
+
+ tmp_cap &= CAPINFO_MASK;
+
+ PRINTM(MINFO, "ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.cap, &tmp_cap,
+ sizeof(IEEEtypes_CapInfo_t));
+
+ /* Information on BSSID descriptor passed to FW */
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: BSSID = %02x-%02x-%02x-%02x-%02x-%02x, SSID = %s\n",
+ padhoc_join->bss_descriptor.bssid[0],
+ padhoc_join->bss_descriptor.bssid[1],
+ padhoc_join->bss_descriptor.bssid[2],
+ padhoc_join->bss_descriptor.bssid[3],
+ padhoc_join->bss_descriptor.bssid[4],
+ padhoc_join->bss_descriptor.bssid[5],
+ padhoc_join->bss_descriptor.ssid);
+
+ for (i = 0; i < WLAN_SUPPORTED_RATES && pbss_desc->supported_rates[i]; i++);
+ rates_size = i;
+
+ /* Copy Data Rates from the Rates recorded in scan response */
+ memset(pmadapter, padhoc_join->bss_descriptor.data_rates, 0,
+ sizeof(padhoc_join->bss_descriptor.data_rates));
+ memcpy(pmadapter, padhoc_join->bss_descriptor.data_rates,
+ pbss_desc->supported_rates, rates_size);
+
+ HEXDUMP("Adapted Rates:", padhoc_join->bss_descriptor.data_rates,
+ rates_size);
+
+ /* Copy the adhoc join rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(pmadapter, &pmpriv->curr_bss_params.data_rates,
+ pbss_desc->supported_rates, rates_size);
+
+ /* Copy the channel information */
+ pmpriv->curr_bss_params.bss_descriptor.channel = pbss_desc->channel;
+ pmpriv->curr_bss_params.band = (t_u8) pbss_desc->bss_band;
+
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ || pmpriv->adhoc_aes_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled)
+ padhoc_join->bss_descriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type
+ = wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, (t_u8) pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv, pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so
+ * adhoc/infra 11h behavior can be properly triggered.
+ * pos modified if data is appended
+ */
+ cmd_append_size += wlan_11h_process_join(pmpriv, &pos,
+ &padhoc_join->bss_descriptor.cap,
+ (t_u8) pbss_desc->bss_band,
+ pbss_desc->channel,
+ &pbss_desc->wlan_11h_bss_info);
+
+ if (pmpriv->sec_info.wpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE or
+ RSN_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie)).vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie)).data[0])
+ , prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmadapter->fw_cap_info)
+ )
+ cmd_append_size += wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(HostCmd_DS_802_11_AD_HOC_JOIN)
+ + S_DS_GEN + cmd_append_size));
+
+ memcpy(pmadapter, &tmp_cap, &padhoc_join->bss_descriptor.cap,
+ sizeof(IEEEtypes_CapInfo_t));
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.cap,
+ &tmp_cap, sizeof(IEEEtypes_CapInfo_t));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_start and
+ * ad_hoc_join
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_ad_hoc(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ HostCmd_DS_802_11_AD_HOC_START_RESULT *padhoc_start_result =
+ &resp->params.adhoc_start_result;
+ HostCmd_DS_802_11_AD_HOC_JOIN_RESULT *padhoc_join_result =
+ &resp->params.adhoc_join_result;
+ BSSDescriptor_t *pbss_desc;
+ t_u16 command = resp->command;
+ t_u8 result = 0;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ if (command == HostCmd_CMD_802_11_AD_HOC_START)
+ result = padhoc_start_result->result;
+ else
+ result = padhoc_join_result->result;
+
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ PRINTM(MERROR, "ADHOC_RESP Failed 0x%x\n", result);
+ if (pmpriv->media_connected == MTRUE)
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ if (pmpriv->adhoc_state == ADHOC_STARTING)
+ pmpriv->adhoc_state = ADHOC_IDLE;
+
+ memset(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+ PRINTM(MINFO, "ADHOC_S_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /* Update the created network descriptor with the new BSSID */
+ memcpy(pmpriv->adapter, pbss_desc->mac_address,
+ padhoc_start_result->bssid, MLAN_MAC_ADDR_LENGTH);
+
+ pmpriv->adhoc_state = ADHOC_STARTED;
+ if (pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ } else {
+ /*
+ * Now the join cmd should be successful.
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ PRINTM(MINFO, "ADHOC_J_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /*
+ * Make a copy of current BSSID descriptor, only needed for join since
+ * the current descriptor is already being used for adhoc start
+ */
+ memcpy(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t));
+
+ pmpriv->adhoc_state = ADHOC_JOINED;
+ }
+
+ PRINTM(MINFO, "ADHOC_RESP: Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[0],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[1],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[2],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[3],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[4],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[5]);
+
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pmpriv->adapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+ wlan_save_curr_bcn(pmpriv);
+
+ done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Associated to a specific BSS discovered in a scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor to associate with.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_associate(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN BSSDescriptor_t * pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 current_bssid[MLAN_MAC_ADDR_LENGTH];
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /* Return error if the pmadapter or table entry is not marked as infra */
+ if ((pmpriv->bss_mode != MLAN_BSS_MODE_INFRA) ||
+ (pbss_desc->bss_mode != MLAN_BSS_MODE_INFRA)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(pmpriv->adapter, &current_bssid,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(current_bssid));
+
+ /* Clear any past association response stored for application retrieval */
+ pmpriv->assoc_rsp_size = 0;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_ASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start an Adhoc Network
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param padhoc_ssid The ssid of the Adhoc Network
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_adhoc_start(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN mlan_802_11_ssid * padhoc_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ t_u8 radar = MFALSE;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /*
+ * If the report indicates no measurement was done, leave the default
+ * return value alone.
+ */
+ if (!pmeas_state->meas_rpt_returned.rpt.basic.map.unmeasured) {
+ radar =
+ pmeas_state->meas_rpt_returned.rpt.basic.map.radar ? MTRUE : MFALSE;
+ }
+
+ if (radar) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+
+ PRINTM(MINFO, "Adhoc Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n", pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, padhoc_ssid);
+#if defined(STA_SUPPORT)
+ if (ret == MLAN_STATUS_SUCCESS)
+ memcpy(pmpriv->adapter, &pmpriv->adhoc_last_start_ssid,
+ padhoc_ssid, sizeof(mlan_802_11_ssid));
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Join an adhoc network found in a previous scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor found in a previous scan
+ * to attempt to join
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_adhoc_join(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN BSSDescriptor_t * pbss_desc)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid =%s\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid_len =%u\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid =%s\n", pbss_desc->ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid len =%u\n", pbss_desc->ssid.ssid_len);
+
+ /* Check if the requested SSID is already joined */
+ if (pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
+ !wlan_ssid_cmp(pmadapter, &pbss_desc->ssid,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid) &&
+ (pmpriv->curr_bss_params.bss_descriptor.bss_mode ==
+ MLAN_BSS_MODE_IBSS)) {
+
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+ "not attempting to re-join\n");
+
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n", pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_JOIN,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send Deauthentication Request or Stop the AdHoc network depending on mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to mlan_ioctl_req structure
+ * @param mac A pointer to mlan_802_11_mac_addr structure
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail, MLAN_STATUS_PENDING--pending
+ */
+mlan_status
+wlan_disconnect(IN mlan_private * pmpriv,
+ IN mlan_ioctl_req * pioctl_req, IN mlan_802_11_mac_addr * mac)
+{
+ mlan_802_11_mac_addr mac_address;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (mac) {
+ if (!memcmp(pmpriv->adapter, mac, zero_mac, sizeof(zero_mac)))
+ memcpy(pmpriv->adapter, (t_u8 *) & mac_address,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, MLAN_MAC_ADDR_LENGTH);
+ else {
+ memcpy(pmpriv->adapter, (t_u8 *) & mac_address,
+ (t_u8 *) mac, MLAN_MAC_ADDR_LENGTH);
+ }
+ } else {
+ memcpy(pmpriv->adapter, (t_u8 *) & mac_address,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, MLAN_MAC_ADDR_LENGTH);
+ }
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, &mac_address);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+
+ } else if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Convert band to radio type used in channel TLV
+ *
+ * @param band Band enumeration to convert to a channel TLV radio type
+ *
+ * @return Radio type designator for use in a channel TLV
+ */
+t_u8
+wlan_band_to_radio_type(IN t_u8 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ default:
+ ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_join.h b/drivers/net/wireless/sd8797/mlan/mlan_join.h
new file mode 100644
index 000000000000..d7091f3a4b28
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_join.h
@@ -0,0 +1,40 @@
+/** @file mlan_join.h
+ *
+ * @brief This file defines the interface for the WLAN infrastructure
+ * and adhoc join routines.
+ *
+ * Driver interface functions and type declarations for the join module
+ * implemented in mlan_join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ *
+ * 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
+******************************************************/
+
+#ifndef _MLAN_JOIN_H_
+#define _MLAN_JOIN_H_
+
+/** Size of buffer allocated to store the association response from firmware */
+#define MRVDRV_ASSOC_RSP_BUF_SIZE 500
+
+/** Size of buffer allocated to store IEs passed to firmware in the assoc req */
+#define MRVDRV_GENIE_BUF_SIZE 256
+
+#endif /* _MLAN_JOIN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_main.h b/drivers/net/wireless/sd8797/mlan/mlan_main.h
new file mode 100644
index 000000000000..44e4f8001201
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_main.h
@@ -0,0 +1,2742 @@
+/** @file mlan_main.h
+ *
+ * @brief This file defines the private and adapter data
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ * 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/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_MAIN_H_
+#define _MLAN_MAIN_H_
+
+#ifdef DEBUG_LEVEL1
+extern t_void(*print_callback) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...);
+
+extern mlan_status(*get_sys_time_callback) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec,
+ OUT t_u32 * pusec);
+
+extern t_u32 drvdbg;
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(msg...) do {if ((drvdbg & MINFO) && (print_callback)) \
+ print_callback(MNULL, MINFO, msg);} while(0)
+#define PRINTM_MWARN(msg...) do {if ((drvdbg & MWARN) && (print_callback)) \
+ print_callback(MNULL, MWARN, msg);} while(0)
+#define PRINTM_MENTRY(msg...) do {if ((drvdbg & MENTRY) && (print_callback)) \
+ print_callback(MNULL, MENTRY, msg);} while(0)
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+do { \
+ if ((level & drvdbg) && (get_sys_time_callback)) \
+ get_sys_time_callback(MNULL, psec, pusec); \
+} while (0)
+
+/** Hexdump for level-2 debugging */
+#define HEXDUMP(x,y,z) \
+do { \
+ if ((drvdbg & (MHEX_DUMP | MINFO)) && (print_callback)) \
+ print_callback(MNULL, MHEX_DUMP | MINFO, x, y, z); \
+} while (0)
+
+#else
+
+#define PRINTM_MINFO(msg...) do {} while (0)
+#define PRINTM_MWARN(msg...) do {} while (0)
+#define PRINTM_MENTRY(msg...) do {} while (0)
+
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+do { \
+ if ((level & drvdbg) && (get_sys_time_callback) \
+ && (level != MINFO) && (level != MWARN)) \
+ get_sys_time_callback(MNULL, psec, pusec); \
+} while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x,y,z) do {} while (0)
+
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(msg...) do {if ((drvdbg & MFW_D) && (print_callback)) \
+ print_callback(MNULL, MFW_D, msg);} while(0)
+#define PRINTM_MCMD_D(msg...) do {if ((drvdbg & MCMD_D) && (print_callback)) \
+ print_callback(MNULL, MCMD_D, msg);} while(0)
+#define PRINTM_MDAT_D(msg...) do {if ((drvdbg & MDAT_D) && (print_callback)) \
+ print_callback(MNULL, MDAT_D, msg);} while(0)
+#define PRINTM_MIF_D(msg...) do {if ((drvdbg & MIF_D) && (print_callback)) \
+ print_callback(MNULL, MIF_D, msg);} while(0)
+
+#define PRINTM_MIOCTL(msg...) do {if ((drvdbg & MIOCTL) && (print_callback)) \
+ print_callback(MNULL, MIOCTL, msg);} while(0)
+#define PRINTM_MINTR(msg...) do {if ((drvdbg & MINTR) && (print_callback)) \
+ print_callback(MNULL, MINTR, msg);} while(0)
+#define PRINTM_MEVENT(msg...) do {if ((drvdbg & MEVENT) && (print_callback)) \
+ print_callback(MNULL, MEVENT, msg);} while(0)
+#define PRINTM_MCMND(msg...) do {if ((drvdbg & MCMND) && (print_callback)) \
+ print_callback(MNULL, MCMND, msg);} while(0)
+#define PRINTM_MDATA(msg...) do {if ((drvdbg & MDATA) && (print_callback)) \
+ print_callback(MNULL, MDATA, msg);} while(0)
+#define PRINTM_MERROR(msg...) do {if ((drvdbg & MERROR) && (print_callback)) \
+ print_callback(MNULL, MERROR, msg);} while(0)
+#define PRINTM_MFATAL(msg...) do {if ((drvdbg & MFATAL) && (print_callback)) \
+ print_callback(MNULL, MFATAL, msg);} while(0)
+#define PRINTM_MMSG(msg...) do {if ((drvdbg & MMSG) && (print_callback)) \
+ print_callback(MNULL, MMSG, msg);} while(0)
+
+#define PRINTM(level,msg...) PRINTM_##level(msg)
+
+/** Log debug message */
+#ifdef __GNUC__
+#define PRINTM_NETINTF(level, pmpriv) \
+do { \
+ if ((drvdbg & level) && pmpriv \
+ && pmpriv->adapter->callbacks.moal_print_netintf) \
+ pmpriv->adapter->callbacks.moal_print_netintf( \
+ pmpriv->adapter->pmoal_handle, \
+ pmpriv->bss_index, level); \
+} while (0)
+#endif /* __GNUC__ */
+
+/** Max hex dump data length */
+#define MAX_DATA_DUMP_LEN 64
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level,x,y,z) \
+do { \
+ if ((drvdbg & level) && print_callback) \
+ print_callback(MNULL, MHEX_DUMP | level, x, y, z); \
+} while (0)
+
+#else /* DEBUG_LEVEL1 */
+
+#define PRINTM(level,msg...) do {} while (0)
+
+#define PRINTM_NETINTF(level, pmpriv) do {} while (0)
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x,y,z) do {} while (0)
+
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) do { } while(0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Log entry point for debugging */
+#define ENTER() \
+do { \
+ PRINTM(MENTRY, "Enter: %s\n", __FUNCTION__); \
+} while (0)
+
+/** Log exit point for debugging */
+#define LEAVE() \
+do { \
+ PRINTM(MENTRY, "Leave: %s\n", __FUNCTION__); \
+} while (0)
+
+/** Find minimum */
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/** Find maximum */
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifdef memset
+#undef memset
+#endif
+/** Memset routine */
+#define memset(adapter, s, c, len) \
+ adapter->callbacks.moal_memset(adapter->pmoal_handle, s, c, len)
+
+#ifdef memmove
+#undef memmove
+#endif
+/** Memmove routine */
+#define memmove(adapter, dest, src, len) \
+ adapter->callbacks.moal_memmove(adapter->pmoal_handle, dest, src, len)
+
+#ifdef memcpy
+#undef memcpy
+#endif
+/** Memcpy routine */
+#define memcpy(adapter, to, from, len) \
+ adapter->callbacks.moal_memcpy(adapter->pmoal_handle, to, from, len)
+
+#ifdef memcmp
+#undef memcmp
+#endif
+/** Memcmp routine */
+#define memcmp(adapter, s1, s2, len) \
+ adapter->callbacks.moal_memcmp(adapter->pmoal_handle, s1, s2, len)
+
+/** Find number of elements */
+#ifndef NELEMENTS
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+/** SWAP: swap t_u8 */
+#define SWAP_U8(a,b) {t_u8 t; t=a; a=b; b=t;}
+
+/** SWAP: swap t_u8 */
+#define SWAP_U16(a,b) {t_u16 t; t=a; a=b; b=t;}
+
+/** MLAN MNULL pointer */
+#define MNULL (0)
+
+/** 16 bits byte swap */
+#define swap_byte_16(x) \
+((t_u16)((((t_u16)(x) & 0x00ffU) << 8) | \
+ (((t_u16)(x) & 0xff00U) >> 8)))
+
+/** 32 bits byte swap */
+#define swap_byte_32(x) \
+((t_u32)((((t_u32)(x) & 0x000000ffUL) << 24) | \
+ (((t_u32)(x) & 0x0000ff00UL) << 8) | \
+ (((t_u32)(x) & 0x00ff0000UL) >> 8) | \
+ (((t_u32)(x) & 0xff000000UL) >> 24)))
+
+/** 64 bits byte swap */
+#define swap_byte_64(x) \
+((t_u64)((t_u64)(((t_u64)(x) & 0x00000000000000ffULL) << 56) | \
+ (t_u64)(((t_u64)(x) & 0x000000000000ff00ULL) << 40) | \
+ (t_u64)(((t_u64)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (t_u64)(((t_u64)(x) & 0x00000000ff000000ULL) << 8) | \
+ (t_u64)(((t_u64)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (t_u64)(((t_u64)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (t_u64)(((t_u64)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (t_u64)(((t_u64)(x) & 0xff00000000000000ULL) >> 56) ))
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert ulong n/w to host */
+#define mlan_ntohl(x) x
+/** Convert host ulong to n/w */
+#define mlan_htonl(x) x
+/** Convert n/w to host */
+#define mlan_ntohs(x) x
+/** Convert host to n/w */
+#define mlan_htons(x) x
+/** Convert from 16 bit little endian format to CPU format */
+#define wlan_le16_to_cpu(x) swap_byte_16(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define wlan_le32_to_cpu(x) swap_byte_32(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define wlan_le64_to_cpu(x) swap_byte_64(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define wlan_cpu_to_le16(x) swap_byte_16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define wlan_cpu_to_le32(x) swap_byte_32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define wlan_cpu_to_le64(x) swap_byte_64(x)
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x) \
+ { \
+ (x)->tx_pkt_length = wlan_cpu_to_le16((x)->tx_pkt_length); \
+ (x)->tx_pkt_offset = wlan_cpu_to_le16((x)->tx_pkt_offset); \
+ (x)->tx_pkt_type = wlan_cpu_to_le16((x)->tx_pkt_type); \
+ (x)->tx_control = wlan_cpu_to_le32((x)->tx_control); \
+ }
+
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x) \
+ { \
+ (x)->rx_pkt_length = wlan_le16_to_cpu((x)->rx_pkt_length); \
+ (x)->rx_pkt_offset = wlan_le16_to_cpu((x)->rx_pkt_offset); \
+ (x)->rx_pkt_type = wlan_le16_to_cpu((x)->rx_pkt_type); \
+ (x)->seq_num = wlan_le16_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert ulong n/w to host */
+#define mlan_ntohl(x) swap_byte_32(x)
+/** Convert host ulong to n/w */
+#define mlan_htonl(x) swap_byte_32(x)
+/** Convert n/w to host */
+#define mlan_ntohs(x) swap_byte_16(x)
+/** Convert host to n/w */
+#define mlan_htons(x) swap_byte_16(x)
+/** Do nothing */
+#define wlan_le16_to_cpu(x) x
+/** Do nothing */
+#define wlan_le32_to_cpu(x) x
+/** Do nothing */
+#define wlan_le64_to_cpu(x) x
+/** Do nothing */
+#define wlan_cpu_to_le16(x) x
+/** Do nothing */
+#define wlan_cpu_to_le32(x) x
+/** Do nothing */
+#define wlan_cpu_to_le64(x) x
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x) do {} while (0)
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x) do {} while (0)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** Global moal_assert_callback */
+extern t_void(*assert_callback) (IN t_void * pmoal_handle, IN t_u32 cond);
+
+/** Assertion */
+#define MASSERT(cond) \
+do { \
+ if (!(cond)) { \
+ PRINTM(MFATAL, "ASSERT: %s: %i\n", __FUNCTION__, __LINE__); \
+ if (assert_callback) { \
+ assert_callback(MNULL, (t_ptr)(cond)); \
+ } else { \
+ do {} while(1); \
+ } \
+ } \
+} while(0)
+
+/** Upload size */
+#define WLAN_UPLD_SIZE (2312)
+
+/** Maximum event buffer size */
+#define MAX_EVENT_SIZE 1024
+
+#ifdef STA_SUPPORT
+/** Maximum buffer size for ARP filter */
+#define ARP_FILTER_MAX_BUF_SIZE 68
+#endif /* STA_SUPPORT */
+
+/** 60 seconds */
+#define MRVDRV_TIMER_60S 60000
+/** 10 seconds */
+#define MRVDRV_TIMER_10S 10000
+/** 5 seconds */
+#define MRVDRV_TIMER_5S 5000
+/** 1 second */
+#define MRVDRV_TIMER_1S 1000
+
+/** Maximum size of multicast list */
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+/** Maximum size of channel */
+#define MRVDRV_MAX_CHANNEL_SIZE 14
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH 32
+/** WEP list macros & data structures */
+/** Size of key buffer in bytes */
+#define MRVL_KEY_BUFFER_SIZE_IN_BYTE 16
+/** Maximum length of WPA key */
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+
+/** Default listen interval */
+#define MLAN_DEFAULT_LISTEN_INTERVAL 10
+
+/** Maximum number of region codes */
+#define MRVDRV_MAX_REGION_CODE 9
+
+/** Maximum number of CFP codes for BG */
+#define MRVDRV_MAX_CFP_CODE_BG 0
+/** Maximum number of CFP codes for A */
+#define MRVDRV_MAX_CFP_CODE_A 5
+
+/** Default region code */
+#define MRVDRV_DEFAULT_REGION_CODE 0x10
+
+/** Default country code */
+#define MRVDRV_DEFAULT_COUNTRY_CODE "US"
+
+/** Default factor for calculating beacon average */
+#define DEFAULT_BCN_AVG_FACTOR 8
+/** Default factor for calculating data average */
+#define DEFAULT_DATA_AVG_FACTOR 8
+
+/** The first valid channel for use */
+#define FIRST_VALID_CHANNEL 0xff
+/** Default Ad-Hoc channel */
+#define DEFAULT_AD_HOC_CHANNEL 6
+/** Default Ad-Hoc channel A */
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+/** Number of WEP keys */
+#define MRVL_NUM_WEP_KEY (4)
+
+/** Default multiple DTIM */
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
+
+/** Default beacon missing timeout */
+#define DEFAULT_BCN_MISS_TIMEOUT 10
+
+/** Maximum buffer space for beacons retrieved from scan responses */
+#define MAX_SCAN_BEACON_BUFFER 16384
+/** Default buffer space for beacons retrieved from scan responses */
+#define DEFAULT_SCAN_BEACON_BUFFER 4096
+
+/**
+ * @brief Buffer pad space for newly allocated beacons/probe responses
+ *
+ * Beacons are typically 6 bytes longer than an equivalent probe response.
+ * For each scan response stored, allocate an extra byte pad at the end to
+ * allow easy expansion to store a beacon in the same memory a probe response
+ * previously contained
+ */
+#define SCAN_BEACON_ENTRY_PAD 6
+
+/** Scan time specified in the channel TLV for each channel for passive scans */
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV for each channel for active scans */
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV for each channel for specific scans */
+#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 110
+
+/**
+ * Max total scan time in milliseconds
+ * The total scan time should be less than scan command timeout value (10s)
+ */
+#define MRVDRV_MAX_TOTAL_SCAN_TIME (MRVDRV_TIMER_10S - MRVDRV_TIMER_1S)
+
+/** Offset for GTK as it has version to skip past for GTK */
+#define RSN_GTK_OUI_OFFSET 2
+
+/** If OUI is not found */
+#define MLAN_OUI_NOT_PRESENT 0
+/** If OUI is found */
+#define MLAN_OUI_PRESENT 1
+
+/** RF antenna selection */
+#define RF_ANTENNA_MASK(n) ((1<<(n))-1)
+/** RF antenna auto select */
+#define RF_ANTENNA_AUTO 0xFFFF
+
+/** Is cmd_resp, event or data packet received? */
+#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
+ adapter->event_received || \
+ adapter->data_received)
+
+/** Type command */
+#define MLAN_TYPE_CMD 1
+/** Type data */
+#define MLAN_TYPE_DATA 0
+/** Type event */
+#define MLAN_TYPE_EVENT 3
+
+/** Maximum numbfer of registers to read for multiple port */
+#define MAX_MP_REGS 64
+/** Maximum port */
+#define MAX_PORT 16
+/** Multi port aggregation packet limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT (8)
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/** Multi port TX aggregation buffer size */
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (16384) /* 16K */
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/** Multi port RX aggregation buffer size */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (16384) /* 16K */
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** High threshold at which to start drop packets */
+#define RX_HIGH_THRESHOLD 1024
+/** Medium threshold at which to disable Rx BA */
+#define RX_MED_THRESHOLD 256
+/** Low threshold to allow Rx BA */
+#define RX_LOW_THRESHOLD 128
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** Info for debug purpose */
+typedef struct _wlan_dbg
+{
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+} wlan_dbg;
+
+/** Hardware status codes */
+typedef enum _WLAN_HARDWARE_STATUS
+{
+ WlanHardwareStatusReady,
+ WlanHardwareStatusInitializing,
+ WlanHardwareStatusInitdone,
+ WlanHardwareStatusReset,
+ WlanHardwareStatusClosing,
+ WlanHardwareStatusNotReady
+} WLAN_HARDWARE_STATUS;
+
+/** WLAN_802_11_POWER_MODE */
+typedef enum _WLAN_802_11_POWER_MODE
+{
+ Wlan802_11PowerModeCAM,
+ Wlan802_11PowerModePSP
+} WLAN_802_11_POWER_MODE;
+
+/** tx param */
+typedef struct _mlan_tx_param
+{
+ /** next packet length */
+ t_u32 next_pkt_len;
+} mlan_tx_param;
+
+/** PS_STATE */
+typedef enum _PS_STATE
+{
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP_CFM,
+ PS_STATE_SLEEP
+} PS_STATE;
+
+/** Minimum flush timer for win size of 1 is 50 ms */
+#define MIN_FLUSH_TIMER_MS 50
+/** Tx BA stream table */
+typedef struct _TxBAStreamTbl TxBAStreamTbl;
+
+/** Add BA parameter data structure */
+typedef struct
+{
+ /** Window size for initiator */
+ t_u32 tx_win_size;
+ /** Window size for receiver */
+ t_u32 rx_win_size;
+ /** Block ack timeout */
+ t_u32 timeout;
+ /** amsdu support for ADDBA request */
+ t_u8 tx_amsdu;
+ /** amsdu support for ADDBA response */
+ t_u8 rx_amsdu;
+} add_ba_param_t;
+
+/** Tx aggregation data structure */
+typedef struct _txAggr_t
+{
+ /** AMPDU user */
+ t_u8 ampdu_user;
+ /** AMPDU AP */
+ t_u8 ampdu_ap;
+ /** AMSDU */
+ t_u8 amsdu;
+} tx_aggr_t;
+
+/** RA list table */
+typedef struct _raListTbl raListTbl;
+
+/** RA list table */
+struct _raListTbl
+{
+ /** Pointer to previous node */
+ raListTbl *pprev;
+ /** Pointer to next node */
+ raListTbl *pnext;
+ /** Buffer list head */
+ mlan_list_head buf_head;
+ /** RA list buffer */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** total packets in RA list */
+ t_u16 total_pkts;
+ /** packets received */
+ t_u16 packet_count;
+ /** packet count threshold to setup BA */
+ t_u8 ba_packet_threshold;
+ /** is 11n enabled */
+ t_u8 is_11n_enabled;
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** tx_pause flag */
+ t_u8 tx_pause;
+};
+
+/** TID table */
+typedef struct _tidTbl
+{
+ /** RA list head */
+ mlan_list_head ra_list;
+ /** Current RA list */
+ raListTbl *ra_list_curr;
+} tid_tbl_t;
+
+/** Highest priority setting for a packet (uses voice AC) */
+#define WMM_HIGHEST_PRIORITY 7
+/** Highest priority TID */
+#define HIGH_PRIO_TID 7
+/** Lowest priority TID */
+#define LOW_PRIO_TID 0
+/** No packet priority (< lowest) */
+#define NO_PKT_PRIO_TID -1
+
+/** Struct of WMM DESC */
+typedef struct _wmm_desc
+{
+ /** TID table */
+ tid_tbl_t tid_tbl_ptr[MAX_NUM_TID];
+ /** Packets out */
+ t_u32 packets_out[MAX_NUM_TID];
+ /** Packets queued */
+ t_u32 pkts_queued[MAX_NUM_TID];
+ /** Spin lock to protect ra_list */
+ t_void *ra_list_spinlock;
+
+ /** AC status */
+ WmmAcStatus_t ac_status[MAX_AC_QUEUES];
+ /** AC downgraded values */
+ mlan_wmm_ac_e ac_down_graded_vals[MAX_AC_QUEUES];
+
+ /** Max driver packet delay sent to the firmware for expiry eval */
+ t_u32 drv_pkt_delay_max;
+
+ /** WMM queue priority table */
+ t_u8 queue_priority[MAX_AC_QUEUES];
+ /** User priority packet transmission control */
+ t_u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
+
+ /** Number of transmit packets queued */
+ mlan_scalar tx_pkts_queued;
+ /** Tracks highest priority with a packet queued */
+ mlan_scalar highest_queued_prio;
+} wmm_desc_t;
+
+/** Security structure */
+typedef struct _wlan_802_11_security_t
+{
+ /** WPA enabled flag */
+ t_u8 wpa_enabled;
+ /** E-Supplicant enabled flag */
+ t_u8 ewpa_enabled;
+ /** WPA2 enabled flag */
+ t_u8 wpa2_enabled;
+ /** WAPI enabled flag */
+ t_u8 wapi_enabled;
+ /** WAPI key on flag */
+ t_u8 wapi_key_on;
+ /** WEP status */
+ WLAN_802_11_WEP_STATUS wep_status;
+ /** Authentication mode */
+ t_u32 authentication_mode;
+ /** Encryption mode */
+ t_u32 encryption_mode;
+} wlan_802_11_security_t;
+
+/** Current Basic Service Set State Structure */
+typedef struct
+{
+ /** BSS descriptor */
+ BSSDescriptor_t bss_descriptor;
+ /** WMM enable? */
+ t_u8 wmm_enabled;
+ /** Uapsd enable?*/
+ t_u8 wmm_uapsd_enabled;
+ /** Band */
+ t_u8 band;
+ /** Number of rates supported */
+ t_u32 num_of_rates;
+ /** Supported rates*/
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+} current_bss_params_t;
+
+/** Sleep_params */
+typedef struct _sleep_params_t
+{
+ /** Sleep parameter error */
+ t_u16 sp_error;
+ /** Sleep parameter offset */
+ t_u16 sp_offset;
+ /** Sleep parameter stable time */
+ t_u16 sp_stable_time;
+ /** Sleep parameter calibration control */
+ t_u8 sp_cal_control;
+ /** Sleep parameter external sleep clock */
+ t_u8 sp_ext_sleep_clk;
+ /** Sleep parameter reserved */
+ t_u16 sp_reserved;
+} sleep_params_t;
+
+/** Sleep_period */
+typedef struct sleep_period_t
+{
+ /** Sleep period */
+ t_u16 period;
+ /** Reserved */
+ t_u16 reserved;
+} sleep_period_t;
+
+/** mrvl_wep_key_t */
+typedef struct _mrvl_wep_key_t
+{
+ /** Length */
+ t_u32 length;
+ /** WEP key index */
+ t_u32 key_index;
+ /** WEP key length */
+ t_u32 key_length;
+ /** WEP keys */
+ t_u8 key_material[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
+} mrvl_wep_key_t;
+
+/** Maximum number of region channel */
+#define MAX_REGION_CHANNEL_NUM 2
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _chan_freq_power_t
+{
+ /** Channel Number */
+ t_u16 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+ /** Max allowed Tx power level */
+ t_u16 max_tx_power;
+ /** TRUE:radar detect required for BAND A or passive scan for BAND B/G;
+ * FALSE:radar detect not required for BAND A or active scan for BAND B/G*/
+ t_bool passive_scan_or_radar_detect;
+ /** TRUE:channel unsupported; FALSE:supported */
+ t_u8 unsupported;
+} chan_freq_power_t;
+
+/** Region-band mapping table */
+typedef struct _region_chan_t
+{
+ /** TRUE if this entry is valid */
+ t_u8 valid;
+ /** Region code for US, Japan ... */
+ t_u8 region;
+ /** Band B/G/A, used for BAND_CONFIG cmd */
+ t_u8 band;
+ /** Actual No. of elements in the array below */
+ t_u8 num_cfp;
+ /** chan-freq-txpower mapping table */
+ chan_freq_power_t *pcfp;
+} region_chan_t;
+
+/** State of 11d */
+typedef enum _state_11d_t
+{
+ DISABLE_11D = 0,
+ ENABLE_11D = 1,
+} state_11d_t;
+
+#define DEFAULT_11D_STATE DISABLE_11D
+
+/** Domain regulatory information */
+typedef struct _wlan_802_11d_domain_reg
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} wlan_802_11d_domain_reg_t;
+
+/** Data for state machine */
+typedef struct _wlan_802_11d_state
+{
+ /** True for enabling 11D */
+ state_11d_t enable_11d;
+ /** True for user enabling 11D */
+ state_11d_t user_enable_11d;
+} wlan_802_11d_state_t;
+
+/** 802.11h State information kept in the 'mlan_private' driver structure */
+typedef struct
+{
+ /** Indicates whether 11h is enabled in the driver */
+ t_bool is_11h_enabled;
+ /** Indicates whether 11h is active in the firmware */
+ t_bool is_11h_active;
+ /** Master device using automatic channel select */
+ t_bool adhoc_auto_sel_chan;
+ /** Set when driver receives a STOP TX event from fw */
+ t_bool tx_disabled;
+} wlan_11h_interface_state_t;
+
+#if defined(UAP_SUPPORT)
+/** UAP get info callback state kept in the 'mlan_private' driver structure */
+typedef struct
+{
+ /** UAP internal callback after wlan_uap_get_channel */
+ /** (parameter is really pointer to mlan_private) */
+ mlan_status(*get_chan_callback) (t_void *);
+ /** current ioctl_req (to be completed in callback) */
+ pmlan_ioctl_req pioctl_req_curr;
+ /** band_cfg from MrvlIEtypes_channel_band_t */
+ t_u8 band_config;
+ /** channel from MrvlIEtypes_channel_band_t */
+ t_u8 channel;
+ /** beacon period (in msec) from MrvlIEtypes_beacon_period_t */
+ t_u16 beacon_period;
+ /** dtim period (no unit) from MrvlIEtypes_dtim_period_t */
+ t_u8 dtim_period;
+} wlan_uap_get_info_cb_t;
+#endif
+
+/** Data structure for WPS information */
+typedef struct
+{
+ /** WPS IE */
+ IEEEtypes_VendorSpecific_t wps_ie;
+ /** Session enable flag */
+ t_u8 session_enable;
+} wps_t;
+
+/** mlan_operations data structure */
+typedef struct _mlan_operations
+{
+ /** cmd init handler */
+ mlan_status(*init_cmd) (IN t_void * priv, IN t_u8 first_bss);
+ /** ioctl handler */
+ mlan_status(*ioctl) (t_void * adapter, pmlan_ioctl_req pioctl_req);
+ /** cmd handler */
+ mlan_status(*prepare_cmd) (IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf);
+ /** cmdresp handler */
+ mlan_status(*process_cmdresp) (IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl);
+ /** rx handler */
+ mlan_status(*process_rx_packet) (IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+ /** event handler */
+ mlan_status(*process_event) (IN t_void * priv);
+ /** txpd handler */
+ t_void *(*process_txpd) (IN t_void * priv, IN pmlan_buffer pmbuf);
+ /** BSS role */
+ mlan_bss_role bss_role;
+} mlan_operations;
+
+/** Private structure for MLAN */
+typedef struct _mlan_private
+{
+ /** Pointer to mlan_adapter */
+ struct _mlan_adapter *adapter;
+ /** BSS index */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS role */
+ t_u8 bss_role;
+ /** BSS Priority */
+ t_u8 bss_priority;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Frame type */
+ t_u8 frame_type;
+ /** MAC address information */
+ t_u8 curr_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Media connection status */
+ t_bool media_connected;
+
+ /** Current packet filter */
+ t_u16 curr_pkt_filter;
+ /** Infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Tx packet control */
+ t_u32 pkt_tx_ctrl;
+
+ /** Tx power level */
+ t_u16 tx_power_level;
+ /** Maximum Tx power level */
+ t_u8 max_tx_power_level;
+ /** Minimum Tx power level */
+ t_u8 min_tx_power_level;
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** tx ht_info */
+ t_u8 tx_htinfo;
+ /** rxpd_htinfo */
+ t_u8 rxpd_htinfo;
+ /** max amsdu size */
+ t_u16 max_amsdu;
+#ifdef UAP_SUPPORT
+ /** UAP 11n flag */
+ t_u8 is_11n_enabled;
+#endif /* UAP_SUPPORT */
+#ifdef UAP_SUPPORT
+#endif /* UAP_SUPPORT */
+#ifdef UAP_SUPPORT
+ /** packet forward control */
+ t_u8 pkt_fwd;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+ /** TX beamforming capability */
+ t_u32 tx_bf_cap;
+ /** Rx PD rate */
+ t_u8 rxpd_rate;
+ /** Rate bitmap */
+ t_u16 rate_bitmap;
+ /** Bitmap rates */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** Data rate */
+ t_u32 data_rate;
+ /** Automatic data rate flag */
+ t_u8 is_data_rate_auto;
+ /** Factor for calculating beacon average */
+ t_u16 bcn_avg_factor;
+ /** Factor for calculating data average */
+ t_u16 data_avg_factor;
+ /** Last data RSSI */
+ t_s16 data_rssi_last;
+ /** Last data Noise Floor */
+ t_s16 data_nf_last;
+ /** Average data RSSI */
+ t_s16 data_rssi_avg;
+ /** Averag data Noise Floor */
+ t_s16 data_nf_avg;
+ /** Last beacon RSSI */
+ t_s16 bcn_rssi_last;
+ /** Last beacon Noise Floor */
+ t_s16 bcn_nf_last;
+ /** Average beacon RSSI */
+ t_s16 bcn_rssi_avg;
+ /** Average beacon Noise Floor */
+ t_s16 bcn_nf_avg;
+
+ /** Attempted BSS descriptor */
+ BSSDescriptor_t *pattempted_bss_desc;
+
+ /** Current SSID/BSSID related parameters*/
+ current_bss_params_t curr_bss_params;
+
+ /** User selected bands */
+ t_u8 config_bands;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** ATIM window */
+ t_u16 atim_window;
+
+ /** AdHoc channel */
+ t_u8 adhoc_channel;
+ /** AdHoc link sensed flag */
+ t_u8 adhoc_is_link_sensed;
+ /** AdHoc operating state */
+ t_u8 adhoc_state;
+#if defined(STA_SUPPORT)
+ /** AdHoc operating state backup */
+ t_u8 adhoc_state_prev;
+ /** AdHoc previous ssid used for Start */
+ mlan_802_11_ssid adhoc_last_start_ssid;
+#endif
+ /** FSM variable for 11d support */
+ wlan_802_11d_state_t state_11d;
+ /** FSM variable for 11h support */
+ wlan_11h_interface_state_t intf_state_11h;
+#if defined(UAP_SUPPORT)
+ /** Whether UAP interface has started */
+ t_bool uap_bss_started;
+ /** state variable for UAP Get Info callback */
+ wlan_uap_get_info_cb_t uap_state_chan_cb;
+#endif
+
+ /** Security related */
+ /** Encryption parameter */
+ wlan_802_11_security_t sec_info;
+ /** WEP keys */
+ mrvl_wep_key_t wep_key[MRVL_NUM_WEP_KEY];
+ /** Current WEP key index */
+ t_u16 wep_key_curr_index;
+ /** EWPA query 0: disable, 1: enable */
+ t_u8 ewpa_query;
+ /** Encryption Key*/
+ t_u8 wpa_ie[256];
+ /** WPA IE length */
+ t_u8 wpa_ie_len;
+ /** GTK set flag */
+ t_u8 wpa_is_gtk_set;
+ /** AES key material */
+ HostCmd_DS_802_11_KEY_MATERIAL aes_key;
+ /** WAPI IE */
+ t_u8 wapi_ie[256];
+ /** WAPI IE length */
+ t_u8 wapi_ie_len;
+ /** Pointer to the station table */
+ mlan_list_head sta_list;
+
+ /** MGMT IE */
+ custom_ie mgmt_ie[MAX_MGMT_IE_INDEX];
+ /** mgmt frame passthru mask */
+ t_u32 mgmt_frame_passthru_mask;
+ /** Advanced Encryption Standard */
+ t_u8 adhoc_aes_enabled;
+ /** WMM required */
+ t_u8 wmm_required;
+ /** WMM enabled */
+ t_u8 wmm_enabled;
+ /** WMM qos info */
+ t_u8 wmm_qosinfo;
+ /** WMM related variable*/
+ wmm_desc_t wmm;
+
+ /** Pointer to the Transmit BA stream table*/
+ mlan_list_head tx_ba_stream_tbl_ptr;
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ tx_aggr_t aggr_prio_tbl[MAX_NUM_TID];
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Struct to store ADDBA parameters */
+ add_ba_param_t add_ba_param;
+ /** last rx_seq */
+ t_u16 rx_seq[MAX_NUM_TID];
+ /** Pointer to the Receive Reordering table*/
+ mlan_list_head rx_reorder_tbl_ptr;
+ /** Lock for Rx packets */
+ t_void *rx_pkt_lock;
+
+#ifdef STA_SUPPORT
+ /** Buffer to store the association response for application retrieval */
+ t_u8 assoc_rsp_buf[MRVDRV_ASSOC_RSP_BUF_SIZE];
+ /** Length of the data stored in assoc_rsp_buf */
+ t_u32 assoc_rsp_size;
+
+ /** Generic IEEE IEs passed from the application to be inserted into the
+ * association request to firmware
+ */
+ t_u8 gen_ie_buf[MRVDRV_GENIE_BUF_SIZE];
+ /** Length of the data stored in gen_ie_buf */
+ t_u8 gen_ie_buf_len;
+
+ t_u8 *pcurr_bcn_buf;
+ t_u32 curr_bcn_size;
+ t_void *curr_bcn_buf_lock;
+
+ /** WPS */
+ wps_t wps;
+#endif /* STA_SUPPORT */
+
+ /** function table */
+ mlan_operations ops;
+
+ /** Port Control mode */
+ t_u8 port_ctrl_mode;
+
+ /** Port open flag */
+ t_u8 port_open;
+
+ /** Port open flag state at time of association attempt */
+ t_u8 prior_port_status;
+
+ /** Scan block flag */
+ t_u8 scan_block;
+ /** IP address operation */
+ t_u32 op_code;
+ /** IP address */
+ t_u8 ip_addr[IPADDR_LEN];
+} mlan_private, *pmlan_private;
+
+/** BA stream status */
+typedef enum _baStatus_e
+{
+ BA_STREAM_NOT_SETUP = 0,
+ BA_STREAM_SETUP_INPROGRESS,
+ BA_STREAM_SETUP_COMPLETE
+} baStatus_e;
+
+/** Tx BA stream table */
+struct _TxBAStreamTbl
+{
+ /** TxBAStreamTbl previous node */
+ TxBAStreamTbl *pprev;
+ /** TxBAStreamTbl next node */
+ TxBAStreamTbl *pnext;
+ /** TID */
+ int tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** BA stream status */
+ baStatus_e ba_status;
+ t_u8 amsdu;
+};
+
+/** RX reorder table */
+typedef struct _RxReorderTbl RxReorderTbl;
+
+typedef struct
+{
+ /** Timer for flushing */
+ t_void *timer;
+ /** Timer set flag */
+ t_u8 timer_is_set;
+ /** RxReorderTbl ptr */
+ RxReorderTbl *ptr;
+ /** Priv pointer */
+ mlan_private *priv;
+} reorder_tmr_cnxt_t;
+
+/** RX reorder table */
+struct _RxReorderTbl
+{
+ /** RxReorderTbl previous node */
+ RxReorderTbl *pprev;
+ /** RxReorderTbl next node */
+ RxReorderTbl *pnext;
+ /** TID */
+ int tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ int start_win;
+ /** Window size */
+ int win_size;
+ /** Pointer to pointer to RxReorderTbl */
+ t_void **rx_reorder_ptr;
+ /** Timer context */
+ reorder_tmr_cnxt_t timer_context;
+ /** BA stream status */
+ baStatus_e ba_status;
+ t_u8 amsdu;
+};
+
+/** BSS priority node */
+typedef struct _mlan_bssprio_node mlan_bssprio_node;
+
+/** BSS priority node */
+struct _mlan_bssprio_node
+{
+ /** Pointer to previous node */
+ mlan_bssprio_node *pprev;
+ /** Pointer to next node */
+ mlan_bssprio_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+};
+
+/** BSS priority table */
+typedef struct _mlan_bssprio_tbl mlan_bssprio_tbl;
+
+/** BSS priority table */
+struct _mlan_bssprio_tbl
+{
+ /** BSS priority list head */
+ mlan_list_head bssprio_head;
+ /** Current priority node */
+ mlan_bssprio_node *bssprio_cur;
+};
+
+/** cmd_ctrl_node */
+typedef struct _cmd_ctrl_node cmd_ctrl_node;
+
+/** _cmd_ctrl_node */
+struct _cmd_ctrl_node
+{
+ /** Pointer to previous node */
+ cmd_ctrl_node *pprev;
+ /** Pointer to next node */
+ cmd_ctrl_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+ /** Command OID for sub-command use */
+ t_u32 cmd_oid;
+ /** Command flag */
+ t_u32 cmd_flag;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *cmdbuf;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *respbuf;
+ /** Command parameter */
+ t_void *pdata_buf;
+ /** Pointer to mlan_ioctl_req if command is from IOCTL */
+ t_void *pioctl_buf;
+ /** pre_allocated mlan_buffer for cmd */
+ mlan_buffer *pmbuf;
+};
+
+/** station node */
+typedef struct _sta_node sta_node;
+
+/** station node*/
+struct _sta_node
+{
+ /** previous node */
+ sta_node *pprev;
+ /** next node */
+ sta_node *pnext;
+ /** station mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** 11n flag */
+ t_u8 is_11n_enabled;
+ /** AMPDU STA */
+ t_u8 ampdu_sta[MAX_NUM_TID];
+ /** last rx_seq */
+ t_u16 rx_seq[MAX_NUM_TID];
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** wapi key on off flag */
+ t_u8 wapi_key_on;
+ /** tx pause status */
+ t_u8 tx_pause;
+};
+
+/** 802.11h State information kept in the 'mlan_adapter' driver structure */
+typedef struct
+{
+ /** Min TX Power capability sent to FW for 11h use and fw power control */
+ t_s8 min_tx_power_capability;
+ /** Max TX Power capability sent to FW for 11h use and fw power control */
+ t_s8 max_tx_power_capability;
+ /** User provisioned local power constraint sent in association requests */
+ t_s8 usr_def_power_constraint;
+ /** Received CHANNEL_SWITCH_ANN event */
+ t_bool recvd_chanswann_event;
+ /** Indicates an interface wants to enable master radar detection */
+ t_bool master_radar_det_enable_pending;
+ /** Indicates an interface wants to enable slave radar detection */
+ t_bool slave_radar_det_enable_pending;
+ /** Indicates whether master radar detection active in the firmware */
+ t_bool is_master_radar_det_active;
+ /** Indicates whether slave radar detection active in the firmware */
+ t_bool is_slave_radar_det_active;
+ /** Quiet IE */
+ IEEEtypes_Quiet_t quiet_ie;
+} wlan_11h_device_state_t;
+
+/** Enumeration for DFS Timestamp represents field */
+enum _dfs_timestamp_repr_e
+{
+ /** Ignore entry */
+ DFS_TS_REPR_NOT_IN_USE = 0,
+ /** NOP (Non-Occupancy Period) start time */
+ DFS_TS_REPR_NOP_START = 1,
+ /** CAC (Channel Availability Check) completion time */
+ DFS_TS_REPR_CAC_COMPLETION
+};
+
+/** DFS Timestamp type used for marking NOP/CAC events */
+typedef struct _wlan_dfs_timestamp_t wlan_dfs_timestamp_t;
+
+/** DFS Timestamp type used for marking NOP/CAC events */
+struct _wlan_dfs_timestamp_t
+{
+ /** Pointer to previous node */
+ wlan_dfs_timestamp_t *pprev;
+ /** Pointer to next node */
+ wlan_dfs_timestamp_t *pnext;
+ /** WLAN Channel number */
+ t_u8 channel;
+ /** What this timestamp represents */
+ t_u8 represents;
+ /** reserved field */
+ t_u16 reserved;
+ /** timestamp - seconds */
+ t_u32 ts_sec;
+ /** timestamp - microseconds */
+ t_u32 ts_usec;
+};
+
+/** DFS State information kept in the 'mlan_adapter' driver structure */
+typedef struct
+{
+ /** Indicates whether DFS channel check is occurring in firmware */
+ t_bool dfs_check_pending;
+ /** Indicates whether DFS channel check found radar */
+ t_bool dfs_radar_found;
+ /** Channel radar is being checked on. BAND_A is assumed. */
+ t_u8 dfs_check_channel;
+ /** Timestamp when we got last report, to determine if data is old or not. */
+ t_u32 dfs_report_time_sec;
+ /** List for holding dfs_timestamps for NOP/CAC events */
+ mlan_list_head dfs_ts_head;
+} wlan_dfs_device_state_t;
+
+/** Enumeration for mlan_ds_11h_radar_det_hndlg stages */
+enum _mlan_ds_11h_rdh_stages
+{
+ RDH_OFF = 0,
+ RDH_CHK_INTFS = 1,
+ 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
+};
+
+/** State info for Radar Detected Handling kept in 'mlan_adapter' */
+typedef struct
+{
+ /** Stage (of Operation) */
+ t_u8 stage;
+ /** Number of interfaces to handle */
+ t_u8 priv_list_count;
+ /** Index of interface in process (used by some stages) */
+ t_u8 priv_curr_idx;
+ /** Current Channel (to leave) */
+ t_u8 curr_channel;
+ /** New Channel (to switch to) */
+ t_u8 new_channel;
+ /** UAP band_config */
+ t_u8 uap_band_cfg;
+ /** BEACON*DTIM period (in msec; max of STA/UAP) */
+ t_u16 max_bcn_dtim_ms;
+ /** List of interfaces to handle */
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+} wlan_radar_det_hndlg_state_t;
+
+#ifdef DFS_TESTING_SUPPORT
+/** DFS/RDH testing exception settings kept in 'mlan_adapter' */
+typedef struct
+{
+ /** user-configured CAC period (in msec) */
+ t_u16 user_cac_period_msec;
+ /** user-configured NOP period (in sec) */
+ t_u16 user_nop_period_sec;
+ /** user-configured skip channel change on radar */
+ t_bool no_channel_change_on_radar;
+ /** user-configured new channel to change to on radar */
+ t_u8 fixed_new_channel_on_radar;
+} wlan_dfs_testing_settings_t;
+#endif /* DFS_SUPPORT_TESTING */
+
+/**
+ * @brief Driver measurement state held in 'mlan_adapter' structure
+ *
+ * Used to record a measurement request that the driver is pending on
+ * the result (received measurement report).
+ */
+typedef struct
+{
+ /**
+ * Dialog token of a pending measurement request/report. Used to
+ * block execution while waiting for the specific dialog token
+ */
+ t_u8 meas_rpt_pend_on;
+
+ /**
+ * Measurement report received from the firmware that we were pending on
+ */
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt_returned;
+
+} wlan_meas_state_t;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/** data structure for SDIO MPA TX */
+typedef struct _sdio_mpa_tx
+{
+ /** allocated buf for tx aggreation */
+ t_u8 *head_ptr;
+ /** multiport tx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport tx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport tx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport tx aggregation ports */
+ t_u32 ports;
+ /** multiport tx aggregation starting port */
+ t_u16 start_port;
+ /** multiport tx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport tx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport tx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_tx;
+#endif
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/** data structure for SDIO MPA RX */
+typedef struct _sdio_mpa_rx
+{
+ /** allocated buf for rx aggreation */
+ t_u8 *head_ptr;
+ /** multiport rx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport rx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport rx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport rx aggregation ports */
+ t_u32 ports;
+ /** multiport rx aggregation starting port */
+ t_u16 start_port;
+
+ /** multiport rx aggregation mbuf array */
+ pmlan_buffer mbuf_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+ /** multiport rx aggregation pkt len array */
+ t_u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+
+ /** multiport rx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport rx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport rx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_rx;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** mlan_init_para structure */
+typedef struct _mlan_init_para
+{
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+ /** 802.11H DFS Master Radar Detect */
+ t_u32 dfs_master_radar_det_en;
+ /** 802.11H DFS Slave Radar Detect */
+ t_u32 dfs_slave_radar_det_en;
+} mlan_init_para, *pmlan_init_para;
+
+/** Adapter data structure for MLAN */
+typedef struct _mlan_adapter
+{
+ /** MOAL handle structure */
+ t_void *pmoal_handle;
+ /** Private pointer */
+ pmlan_private priv[MLAN_MAX_BSS_NUM];
+ /** Total number of Priv number */
+ t_u8 priv_num;
+ /** Priority table for bss */
+ mlan_bssprio_tbl bssprio_tbl[MLAN_MAX_BSS_NUM];
+ /** Callback table */
+ mlan_callbacks callbacks;
+ /** Init parameters */
+ mlan_init_para init_para;
+
+ /** mlan_lock for init/shutdown */
+ t_void *pmlan_lock;
+ /** main_proc_lock for main_process */
+ t_void *pmain_proc_lock;
+ /** mlan_processing */
+ t_u32 mlan_processing;
+ /** Max tx buf size */
+ t_u16 max_tx_buf_size;
+ /** Tx buf size */
+ t_u16 tx_buf_size;
+ /** current tx buf size in fw */
+ t_u16 curr_tx_buf_size;
+ /** IO port */
+ t_u32 ioport;
+
+ /** STATUS variables */
+ WLAN_HARDWARE_STATUS hw_status;
+ /** PnP SUPPORT */
+ t_u8 surprise_removed;
+
+ /** Radio on flag */
+ t_u16 radio_on;
+
+ /** Firmware release number */
+ t_u32 fw_release_number;
+
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+
+ /** Firmware capability information */
+ t_u32 fw_cap_info;
+ /** pint_lock for interrupt handling */
+ t_void *pint_lock;
+ /** Interrupt status */
+ t_u8 sdio_ireg;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** SDIO end port from txbufcfg */
+ t_u16 mp_end_port;
+ /** SDIO port mask calculated based on txbufcfg end port */
+ t_u32 mp_data_port_mask;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Array to store values of SDIO multiple port group registers */
+ t_u8 *mp_regs;
+ /** allocated buf to read SDIO multiple port group registers */
+ t_u8 *mp_regs_buf;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** data structure for SDIO MPA TX */
+ sdio_mpa_tx mpa_tx;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** data structure for SDIO MPA RX */
+ sdio_mpa_rx mpa_rx;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+
+ /** Event cause */
+ t_u32 event_cause;
+ /** Event buffer */
+ pmlan_buffer pmlan_buffer_event;
+ /** Upload length */
+ t_u32 upld_len;
+ /** Upload buffer*/
+ t_u8 upld_buf[WLAN_UPLD_SIZE];
+ /** Data sent:
+ * TRUE - Data is sent to fw, no Tx Done received
+ * FALSE - Tx done received for previous Tx
+ */
+ t_u8 data_sent;
+ /** CMD sent:
+ * TRUE - CMD is sent to fw, no CMD Done received
+ * FALSE - CMD done received for previous CMD
+ */
+ t_u8 cmd_sent;
+ /** CMD Response received:
+ * TRUE - CMD is response is received from fw, and yet to process
+ * FALSE - No cmd response to process
+ */
+ t_u8 cmd_resp_received;
+ /** Event received:
+ * TRUE - Event received from fw, and yet to process
+ * FALSE - No events to process
+ */
+ t_u8 event_received;
+
+ /** Data received:
+ * TRUE - Data received from fw
+ * FALSE - No Data received
+ */
+ t_u8 data_received;
+
+ /** Command-related variables */
+ /** Command sequence number */
+ t_u16 seq_num;
+ /** Command controller nodes */
+ cmd_ctrl_node *cmd_pool;
+ /** Current Command */
+ cmd_ctrl_node *curr_cmd;
+ /** mlan_lock for command */
+ t_void *pmlan_cmd_lock;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Last init fw command id */
+ t_u16 last_init_cmd;
+ /** Command timer */
+ t_void *pmlan_cmd_timer;
+ /** Command timer set flag */
+ t_u8 cmd_timer_is_set;
+
+ /** Command Queues */
+ /** Free command buffers */
+ mlan_list_head cmd_free_q;
+ /** Pending command buffers */
+ mlan_list_head cmd_pending_q;
+ /** Command queue for scanning */
+ mlan_list_head scan_pending_q;
+ /** mlan_processing */
+ t_u32 scan_processing;
+
+ /** Region code */
+ t_u16 region_code;
+ /** Region Channel data */
+ region_chan_t region_channel[MAX_REGION_CHANNEL_NUM];
+ /** CFP table code for 2.4GHz */
+ t_u8 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u8 cfp_code_a;
+#ifdef STA_SUPPORT
+ /** Universal Channel data */
+ region_chan_t universal_channel[MAX_REGION_CHANNEL_NUM];
+ /** Parsed region channel */
+ parsed_region_chan_11d_t parsed_region_chan;
+#endif /* STA_SUPPORT */
+ /** 11D and Domain Regulatory Data */
+ wlan_802_11d_domain_reg_t domain_reg;
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** FSM variable for 11h support */
+ wlan_11h_device_state_t state_11h;
+ /** FSM variable for DFS support */
+ wlan_dfs_device_state_t state_dfs;
+ /** FSM variable for RDH support */
+ wlan_radar_det_hndlg_state_t state_rdh;
+#ifdef DFS_TESTING_SUPPORT
+ /** User configured settings for DFS testing */
+ wlan_dfs_testing_settings_t dfs_test_params;
+#endif
+ /** FSM variable for MEAS support */
+ wlan_meas_state_t state_meas;
+ /** Scan table */
+ BSSDescriptor_t *pscan_table;
+ /** scan age in secs */
+ t_u32 age_in_secs;
+ t_u8 bgscan_reported;
+
+ /** Number of records in the scan table */
+ t_u32 num_in_scan_table;
+ /** Scan probes */
+ t_u16 scan_probes;
+
+ /** Scan type */
+ t_u8 scan_type;
+ /** Scan mode */
+ t_u32 scan_mode;
+ /** Specific scan time */
+ t_u16 specific_scan_time;
+ /** Active scan time */
+ t_u16 active_scan_time;
+ /** Passive scan time */
+ t_u16 passive_scan_time;
+ /** Extended scan or legacy scan */
+ t_u8 ext_scan;
+ t_u16 bcn_buf_size;
+ /** Beacon buffer */
+ t_u8 *bcn_buf;
+ /** Pointer to valid beacon buffer end */
+ t_u8 *pbcn_buf_end;
+
+ /** F/W supported bands */
+ t_u8 fw_bands;
+ /** User selected band to start adhoc network */
+ t_u8 adhoc_start_band;
+ /** User selected bands */
+ t_u8 config_bands;
+ /** Pointer to channel list last sent to the firmware for scanning */
+ ChanScanParamSet_t *pscan_channels;
+
+ /** Tx lock flag */
+ t_u8 tx_lock_flag;
+
+ /** sleep_params_t */
+ sleep_params_t sleep_params;
+ /** sleep_period_t (Enhanced Power Save) */
+ sleep_period_t sleep_period;
+
+ /** Power Save mode */
+ /**
+ * Wlan802_11PowerModeCAM = disable
+ * Wlan802_11PowerModePSP = enable
+ */
+ t_u16 ps_mode;
+ /** Power Save state */
+ t_u32 ps_state;
+ /** Need to wakeup flag */
+ t_u8 need_to_wakeup;
+
+ /** Multiple DTIM */
+ t_u16 multiple_dtim;
+ /** Local listen interval */
+ t_u16 local_listen_interval;
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+
+ /** Power save confirm sleep command buffer */
+ pmlan_buffer psleep_cfm;
+ /** Beacon miss timeout */
+ t_u16 bcn_miss_time_out;
+
+ /** AdHoc awake period */
+ t_u16 adhoc_awake_period;
+
+ /** Deep Sleep flag */
+ t_u8 is_deep_sleep;
+ /** Idle time */
+ t_u16 idle_time;
+ /** Auto Deep Sleep enabled at init time */
+ t_u8 init_auto_ds;
+
+ /** delay null pkt flag */
+ t_u8 delay_null_pkt;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+ /** Enhanced PS mode */
+ t_u16 enhanced_ps_mode;
+ /** Device wakeup required flag */
+ t_u8 pm_wakeup_card_req;
+
+ /** Gen NULL pkg */
+ t_u16 gen_null_pkt;
+
+ /** PPS/UAPSD mode flag */
+ t_u16 pps_uapsd_mode;
+ /** Number of wakeup tries */
+ t_u32 pm_wakeup_fw_try;
+
+ /** Host Sleep configured flag */
+ t_u8 is_hs_configured;
+ /** Host Sleep configuration */
+ hs_config_param hs_cfg;
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** Event body */
+ t_u8 event_body[MAX_EVENT_SIZE];
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** 802.11n Device Capabilities for 2.4GHz */
+ t_u32 usr_dot_11n_dev_cap_bg;
+ /** 802.11n Device Capabilities for 5GHz */
+ t_u32 usr_dot_11n_dev_cap_a;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 usr_dev_mcs_support;
+#ifdef STA_SUPPORT
+ /** Enable 11n support for adhoc start */
+ t_u8 adhoc_11n_enabled;
+ /** Adhoc Secondary Channel Bandwidth */
+ t_u8 chan_bandwidth;
+#endif /* STA_SUPPORT */
+
+ /** max mgmt IE index in device */
+ t_u16 max_mgmt_ie_index;
+
+#ifdef MFG_CMD_SUPPORT
+ t_u32 mfg_mode;
+#endif
+ /** Debug */
+ wlan_dbg dbg;
+
+ /** RX pending for forwarding packets */
+ t_u16 pending_bridge_pkts;
+
+#ifdef STA_SUPPORT
+ /** ARP filter buffer */
+ t_u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
+ /** ARP filter buffer size */
+ t_u32 arp_filter_size;
+#endif /* STA_SUPPORT */
+
+ /** Bypass TX queue */
+ mlan_list_head bypass_txq;
+#if defined(STA_SUPPORT)
+ /** warm-reset IOCTL request buffer pointer */
+ pmlan_ioctl_req pwarm_reset_ioctl_req;
+#endif
+ /** Extended SCAN IOCTL request buffer pointer */
+ pmlan_ioctl_req pext_scan_ioctl_req;
+ /** Cal data pointer */
+ t_u8 *pcal_data;
+ /** Cal data length */
+ t_u32 cal_data_len;
+
+} mlan_adapter, *pmlan_adapter;
+
+/** Ethernet packet type for EAPOL */
+#define MLAN_ETHER_PKT_TYPE_EAPOL (0x888E)
+/** Ethernet packet type for WAPI */
+#define MLAN_ETHER_PKT_TYPE_WAPI (0x88B4)
+/** Ethernet packet type offset */
+#define MLAN_ETHER_PKT_TYPE_OFFSET (12)
+
+mlan_status wlan_init_lock_list(IN pmlan_adapter pmadapter);
+t_void wlan_free_lock_list(IN pmlan_adapter pmadapter);
+mlan_status wlan_init_timer(IN pmlan_adapter pmadapter);
+t_void wlan_free_timer(IN pmlan_adapter pmadapter);
+
+/* Function prototype */
+/** Download firmware */
+mlan_status wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw);
+
+/** Initialize firmware */
+mlan_status wlan_init_fw(IN pmlan_adapter pmadapter);
+
+/** Initialize firmware complete */
+mlan_status wlan_init_fw_complete(IN pmlan_adapter pmadapter);
+
+/** Shutdown firmware complete */
+mlan_status wlan_shutdown_fw_complete(IN pmlan_adapter pmadapter);
+
+/** Receive event */
+mlan_status wlan_recv_event(pmlan_private priv,
+ mlan_event_id event_id, t_void * pmevent);
+
+/** Initialize mlan_adapter structure */
+t_void wlan_init_adapter(IN pmlan_adapter pmadapter);
+
+/** Initialize mlan_private structure */
+mlan_status wlan_init_priv(IN pmlan_private priv);
+
+/** Process event */
+mlan_status wlan_process_event(pmlan_adapter pmadapter);
+
+/** Prepare command */
+mlan_status wlan_prepare_cmd(IN pmlan_private priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf);
+
+/** cmd timeout handler */
+t_void wlan_cmd_timeout_func(t_void * FunctionContext);
+/** process host cmd */
+mlan_status wlan_misc_ioctl_host_cmd(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** process init/shutdown cmd*/
+mlan_status wlan_misc_ioctl_init_shutdown(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** process debug info */
+mlan_status wlan_get_info_debug_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Set/Get BSS role */
+mlan_status wlan_bss_ioctl_bss_role(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+#endif
+
+mlan_status wlan_set_ewpa_mode(mlan_private * priv,
+ mlan_ds_passphrase * psec_pp);
+mlan_status wlan_find_bss(mlan_private * pmpriv, pmlan_ioctl_req pioctl_req);
+
+/** Allocate memory for adapter structure members */
+mlan_status wlan_allocate_adapter(pmlan_adapter pmadapter);
+/** Free adapter */
+t_void wlan_free_adapter(pmlan_adapter pmadapter);
+/** Free priv */
+t_void wlan_free_priv(mlan_private * pmpriv);
+/** Allocate command buffer */
+mlan_status wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter);
+/** Free command buffer */
+mlan_status wlan_free_cmd_buffer(IN mlan_adapter * pmadapter);
+/** Request command lock */
+t_void wlan_request_cmd_lock(mlan_adapter * pmadapter);
+/** Release command lock */
+t_void wlan_release_cmd_lock(mlan_adapter * pmadapter);
+#ifdef STA_SUPPORT
+/** Flush the scan pending queue */
+t_void wlan_flush_scan_queue(pmlan_adapter pmadapter);
+#endif
+/**Cancel pending command */
+t_void wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter);
+/**Cancel pending ioctl */
+t_void wlan_cancel_pending_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+/** Insert command to free queue */
+t_void wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node);
+
+/** Insert command to pending queue */
+t_void wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node,
+ IN t_u32 addtail);
+
+/** Execute next command */
+mlan_status wlan_exec_next_cmd(mlan_adapter * pmadapter);
+/** Proecess command response */
+mlan_status wlan_process_cmdresp(mlan_adapter * pmadapter);
+/** Handle received packet, has extra handling for aggregate packets */
+mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Process transmission */
+mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param * tx_param);
+/** Transmit a null data packet */
+mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags);
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+mlan_status wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
+ t_u32 mpa_tx_buf_size,
+ t_u32 mpa_rx_buf_size);
+
+mlan_status wlan_free_sdio_mpa_buffers(IN mlan_adapter * pmadapter);
+#endif
+
+/** Process write data complete */
+mlan_status wlan_write_data_complete(pmlan_adapter pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Process receive packet complete */
+mlan_status wlan_recv_packet_complete(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Clean Tx Rx queues */
+t_void wlan_clean_txrx(pmlan_private priv);
+
+t_void wlan_add_buf_bypass_txqueue(mlan_adapter * pmadapter,
+ pmlan_buffer pmbuf);
+t_void wlan_process_bypass_tx(mlan_adapter * pmadapter);
+t_void wlan_cleanup_bypass_txq(mlan_adapter * pmadapter);
+t_u8 wlan_bypass_tx_list_empty(mlan_adapter * pmadapter);
+
+/** Check if this is the last packet */
+t_u8 wlan_check_last_packet_indication(pmlan_private priv);
+
+/** function to allocate a mlan_buffer */
+pmlan_buffer wlan_alloc_mlan_buffer(mlan_adapter * pmadapter, t_u32 data_len,
+ t_u32 head_room, t_u32 malloc_flag);
+/** function to free a mlan_buffer */
+t_void wlan_free_mlan_buffer(mlan_adapter * pmadapter, pmlan_buffer pmbuf);
+
+/** command resp handler for version ext */
+mlan_status wlan_ret_ver_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+
+/** command resp handler for rx mgmt forward registration */
+mlan_status wlan_ret_rx_mgmt_ind(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+
+/** Check Power Save condition */
+t_void wlan_check_ps_cond(mlan_adapter * pmadapter);
+
+/** handle command for enhanced power save mode */
+mlan_status wlan_cmd_enh_power_mode(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u16 ps_bitmap, IN t_void * pdata_buf);
+/** handle command resp for enhanced power save mode */
+mlan_status wlan_ret_enh_power_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+/** handle commnand for cfg data */
+mlan_status wlan_cmd_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+/** handle command resp for cfg data */
+mlan_status wlan_ret_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Process sleep confirm command response */
+void wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
+ t_u32 len);
+
+/** Perform hs related activities on receving the power up interrupt */
+void wlan_process_hs_config(pmlan_adapter pmadapter);
+
+mlan_status wlan_pm_reset_card(pmlan_adapter adapter);
+mlan_status wlan_pm_wakeup_card(pmlan_adapter pmadapter);
+
+mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private * priv, t_u8 * payload,
+ t_u32 payload_len);
+
+mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#ifdef WIFI_DIRECT_SUPPORT
+mlan_status wlan_bss_ioctl_wifi_direct_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_radio_ioctl_remain_chan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+#endif
+
+/** get pm info */
+mlan_status wlan_get_pm_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_radio_ctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_ant_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+mlan_status wlan_ret_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_rate_ioctl_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+mlan_status wlan_ret_802_11_tx_rate_query(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+t_void wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated);
+/** Handles the command response of hs_cfg */
+mlan_status wlan_ret_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+/** Sends HS_WAKEUP event to applications */
+t_void wlan_host_sleep_wakeup_event(pmlan_private priv);
+
+/** send adapter specific init cmd to firmware */
+mlan_status wlan_adapter_init_cmd(IN pmlan_adapter pmadapter);
+
+#ifdef STA_SUPPORT
+/** Process received packet */
+mlan_status wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** ioctl handler for station mode */
+mlan_status wlan_ops_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req);
+
+/** cmd handler for station mode */
+mlan_status wlan_ops_sta_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf,
+ IN t_void * pcmd_buf);
+
+/** cmdresp handler for station mode */
+mlan_status wlan_ops_sta_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf,
+ IN t_void * pioctl);
+
+/** rx handler for station mode */
+mlan_status wlan_ops_sta_process_rx_packet(IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+
+/** event handler for station mode */
+mlan_status wlan_ops_sta_process_event(IN t_void * priv);
+
+/** fill txpd for station mode */
+t_void *wlan_ops_sta_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf);
+
+/** send init cmd to firmware for station mode */
+mlan_status wlan_ops_sta_init_cmd(IN t_void * priv, IN t_u8 first_bss);
+
+/** Flush the scan table */
+mlan_status wlan_flush_scan_table(IN pmlan_adapter pmadapter);
+
+/** Scan for networks */
+mlan_status wlan_scan_networks(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN const wlan_user_scan_cfg * puser_scan_in);
+
+/** Scan for specific SSID */
+mlan_status wlan_scan_specific_ssid(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN mlan_802_11_ssid * preq_ssid);
+
+/** Scan command handler */
+mlan_status wlan_cmd_802_11_scan(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+
+/** Queue scan command handler */
+t_void wlan_queue_scan_cmd(IN mlan_private * pmpriv,
+ IN cmd_ctrl_node * pcmd_node);
+
+/** Handler for scan command response */
+mlan_status wlan_ret_802_11_scan(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Extended scan command handler */
+mlan_status wlan_cmd_802_11_scan_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+/** Handler for extended scan command response */
+mlan_status wlan_ret_802_11_scan_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+/** Handler event for extended scan report */
+mlan_status wlan_handle_event_ext_scan_report(IN mlan_private * pmpriv,
+ IN mlan_buffer * pmbuf);
+
+/** check network compatibility */
+t_s32 wlan_is_network_compatible(IN mlan_private * pmpriv,
+ IN t_u32 index, IN t_u32 mode);
+
+/** Find an SSID in a list */
+t_s32 wlan_find_ssid_in_list(IN pmlan_private pmpriv,
+ IN mlan_802_11_ssid * ssid,
+ IN t_u8 * bssid, IN t_u32 mode);
+
+/** Find a BSSID in a list */
+t_s32 wlan_find_bssid_in_list(IN mlan_private * pmpriv,
+ IN t_u8 * bssid, IN t_u32 mode);
+
+/** Find best network */
+mlan_status wlan_find_best_network(IN mlan_private * pmpriv,
+ OUT mlan_ssid_bssid * preq_ssid_bssid);
+
+/** Compare two SSIDs */
+t_s32 wlan_ssid_cmp(IN pmlan_adapter pmadapter,
+ IN mlan_802_11_ssid * ssid1, IN mlan_802_11_ssid * ssid2);
+
+/** Associate */
+mlan_status wlan_associate(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN BSSDescriptor_t * pBSSDesc);
+
+/** Associate command handler */
+mlan_status wlan_cmd_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Handler for association command response */
+mlan_status wlan_ret_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Reset connected state */
+t_void wlan_reset_connect_state(IN pmlan_private priv, IN t_u8 drv_disconnect);
+
+t_void wlan_2040_coex_event(pmlan_private pmpriv);
+
+/** convert band to radio type */
+t_u8 wlan_band_to_radio_type(IN t_u8 band);
+
+/** Disconnect */
+mlan_status wlan_disconnect(IN mlan_private * pmpriv,
+ IN mlan_ioctl_req * pioctl_req,
+ IN mlan_802_11_mac_addr * mac);
+
+/** Ad-Hoc start */
+mlan_status wlan_adhoc_start(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN mlan_802_11_ssid * padhoc_ssid);
+
+/** Ad-Hoc join */
+mlan_status wlan_adhoc_join(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN BSSDescriptor_t * pBSSDesc);
+
+/** Ad-Hoc start command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_start(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Ad-Hoc command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_join(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Handler for Ad-Hoc commands */
+mlan_status wlan_ret_802_11_ad_hoc(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Handler for bgscan query commands */
+mlan_status wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+/** Handler for bgscan config command */
+mlan_status wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+/** Hander for bgscan config command response */
+mlan_status wlan_ret_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+mlan_status wlan_ret_802_11_bgscan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+/** Get Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
+ t_u8 band, t_u16 channel,
+ region_chan_t *
+ region_channel);
+/** Find Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_find_cfp_by_band_and_channel(mlan_adapter * pmadapter,
+ t_u8 band, t_u16 channel);
+/** Find Channel-Frequency-Power by band and frequency */
+chan_freq_power_t *wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter,
+ t_u8 band, t_u32 freq);
+/** Get Tx power of channel from Channel-Frequency-Power */
+t_u8 wlan_get_txpwr_of_chan_from_cfp(mlan_private * pmpriv, t_u8 channel);
+/** find frequency from band and channel */
+t_u32 wlan_find_freq_from_band_chan(t_u8, t_u8);
+
+/* Save a beacon buffer of the current bss descriptor */
+t_void wlan_save_curr_bcn(IN mlan_private * pmpriv);
+/* Free a beacon buffer of the current bss descriptor */
+t_void wlan_free_curr_bcn(IN mlan_private * pmpriv);
+
+#endif /* STA_SUPPORT */
+
+/* Rate related functions */
+/** Convert index into data rate */
+t_u32 wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index,
+ t_u8 ht_info);
+/** Get active data rates */
+t_u32 wlan_get_active_data_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates);
+/** Get supported data rates */
+t_u32 wlan_get_supported_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates);
+/** Convert data rate to index */
+t_u8 wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate);
+/** Check if rate is auto */
+t_u8 wlan_is_rate_auto(mlan_private * pmpriv);
+/** Get rate index */
+int wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rateBitmap, int size);
+
+/* CFP related functions */
+/** Region code index table */
+extern t_u16 region_code_index[MRVDRV_MAX_REGION_CODE];
+/** The table to keep CFP code for BG */
+extern t_u16 cfp_code_index_bg[MRVDRV_MAX_CFP_CODE_BG];
+/** The table to keep CFP code for A */
+extern t_u16 cfp_code_index_a[MRVDRV_MAX_CFP_CODE_A];
+/** Set region table */
+mlan_status wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band);
+/** Get radar detection requirements*/
+t_bool wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl);
+/** check if scan type is passive for b/g band*/
+t_bool wlan_bg_scan_type_is_passive(mlan_private * priv, t_u8 chnl);
+
+/* 802.11D related functions */
+/** Initialize 11D */
+t_void wlan_11d_priv_init(mlan_private * pmpriv);
+/** Initialize 11D */
+t_void wlan_11d_init(mlan_adapter * pmadapter);
+/** Enable 11D */
+mlan_status wlan_11d_enable(mlan_private * pmpriv, t_void * pioctl_buf,
+ state_11d_t flag);
+/** Get if 11D is enabled */
+t_bool wlan_11d_is_enabled(mlan_private * pmpriv);
+/** Get if priv is station */
+t_bool wlan_is_station(mlan_private * pmpriv);
+/** Command handler for 11D country info */
+mlan_status wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd,
+ t_u16 cmd_action);
+/** Handler for 11D country info command response */
+mlan_status wlan_ret_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * resp);
+#ifdef STA_SUPPORT
+/** Convert channel to frequency */
+t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band);
+/** Set 11D universal table */
+mlan_status wlan_11d_set_universaltable(mlan_private * pmpriv, t_u8 band);
+/** Clear 11D region table */
+mlan_status wlan_11d_clear_parsedtable(mlan_private * pmpriv);
+/** Create 11D country information for downloading */
+mlan_status wlan_11d_create_dnld_countryinfo(mlan_private * pmpriv, t_u8 band);
+/** Get scan type from 11D info */
+t_u8 wlan_11d_get_scan_type(pmlan_adapter pmadapter, t_u8 band, t_u8 chan,
+ parsed_region_chan_11d_t * parsed_region_chan);
+/** Parse 11D country info */
+mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private * pmpriv,
+ BSSDescriptor_t * pBSSDesc);
+/** Prepare 11D domain information for download */
+mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private * pmpriv);
+/** Parse 11D country information into domain info */
+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);
+/** Configure 11D domain info command */
+mlan_status wlan_11d_cfg_domain_info(IN pmlan_adapter pmadapter,
+ IN mlan_ioctl_req * pioctl_req);
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Handle 11D domain information from UAP */
+mlan_status wlan_11d_handle_uap_domain_info(mlan_private * pmpriv,
+ t_u8 band,
+ t_u8 * domain_tlv,
+ t_void * pioctl_buf);
+#endif
+
+/** This function converts region string to CFP table code */
+mlan_status wlan_misc_country_2_cfp_table_code(IN pmlan_adapter pmadapter,
+ IN t_u8 * country_code,
+ OUT t_u8 * cfp_bg,
+ OUT t_u8 * cfp_a);
+
+/** check if station list is empty */
+t_u8 wlan_is_station_list_empty(mlan_private * priv);
+/** get station node */
+sta_node *wlan_get_station_entry(mlan_private * priv, t_u8 * mac);
+/** delete station list */
+t_void wlan_delete_station_list(pmlan_private priv);
+/** delete station entry */
+t_void wlan_delete_station_entry(mlan_private * priv, t_u8 * mac);
+/** add station entry */
+sta_node *wlan_add_station_entry(mlan_private * priv, t_u8 * mac);
+/** process uap rx packet */
+
+/** find specific ie */
+t_u8 *wlan_get_specific_ie(pmlan_private priv, t_u8 * ie_buf, t_u8 ie_len,
+ IEEEtypes_ElementId_e id);
+
+/**
+ * @brief This function checks tx_pause flag for peer
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_tx_pause(mlan_private * priv, t_u8 * ra)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, ra))) {
+ return sta_ptr->tx_pause;
+ }
+ return MFALSE;
+}
+
+t_void wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac,
+ t_u8 tx_pause);
+
+#ifdef UAP_SUPPORT
+mlan_status wlan_process_uap_rx_packet(IN mlan_private * priv,
+ IN pmlan_buffer pmbuf);
+t_void wlan_drop_tx_pkts(pmlan_private priv);
+#endif /* UAP_SUPPORT */
+
+#ifdef UAP_SUPPORT
+/* process the recevied packet and bridge the packet */
+mlan_status wlan_uap_recv_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf);
+#endif /* UAP_SUPPORT */
+
+mlan_status wlan_misc_ioctl_custom_ie_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req,
+ IN t_bool send_ioctl);
+
+mlan_status wlan_cmd_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd);
+mlan_status wlan_ret_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+mlan_status wlan_cmd_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_cmd_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_get_info_ver_ext(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_reg_rx_mgmt_ind(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+#ifdef DEBUG_LEVEL1
+mlan_status wlan_set_drvdbg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+#endif
+
+mlan_status wlan_misc_otp_user_data(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+/**
+ * @brief RA based queueing
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+queuing_ra_based(pmlan_private priv)
+{
+ /*
+ * Currently we assume if we are in Infra, then DA=RA. This might not be
+ * true in the future
+ */
+ if ((priv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA))
+ return MFALSE;
+
+ return MTRUE;
+}
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to Dest Buf
+ * @param pos The position for copy
+ * @param src A pointer to Src Buf
+ * @param len The len of Src Buf
+ *
+ * @return Number of Rates copied
+ */
+static INLINE t_u32
+wlan_copy_rates(t_u8 * dest, t_u32 pos, t_u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= sizeof(WLAN_802_11_RATES))
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/**
+ * @brief strlen
+ *
+ * @param str A pointer to string
+ *
+ * @return Length of string
+ */
+static INLINE t_u32
+wlan_strlen(const t_s8 * str)
+{
+ t_u32 i;
+
+ for (i = 0; str[i] != 0; i++) {
+ }
+ return i;
+}
+
+/**
+ * @brief iscdigit
+ *
+ * @param chr A char
+ *
+ * @return Non zero if chr is a hex, else 0
+ */
+static INLINE t_u32
+wlan_isxdigit(t_u8 chr)
+{
+ return ((chr <= 'f' && chr >= 'a') || (chr <= 'F' && chr >= 'A') ||
+ (chr <= '9' && chr >= '0'));
+}
+
+/**
+ * @brief isspace
+ *
+ * @param A chr
+ *
+ * @return Non zero if chr is space etc, else 0
+ */
+static INLINE t_u32
+wlan_isspace(t_u8 chr)
+{
+ return (chr <= ' ' && (chr == ' ' || (chr <= 13 && chr >= 9)));
+}
+
+/** delay unit */
+typedef enum _delay_unit
+{
+ USEC,
+ MSEC,
+ SEC,
+} t_delay_unit;
+
+/** delay function */
+t_void wlan_delay_func(mlan_adapter * pmadapter, t_u32 delay, t_delay_unit u);
+
+/** delay function wrapper */
+#define wlan_delay(p, n) wlan_delay_func(p, n, SEC)
+/** delay function wrapper */
+#define wlan_mdelay(p, n) wlan_delay_func(p, n, MSEC)
+/** delay function wrapper */
+#define wlan_udelay(p, n) wlan_delay_func(p, n, USEC)
+
+/** Function to check if any command is pending in the queue */
+#define IS_COMMAND_PENDING(pmadapter) ((cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, \
+ &pmadapter->cmd_pending_q,\
+ pmadapter->callbacks.moal_spin_lock,\
+ pmadapter->callbacks.moal_spin_unlock))
+
+/** Get BSS number from priv */
+#define GET_BSS_NUM(priv) (priv)->bss_num
+/**
+ * @brief This function returns priv based on the BSS num and BSS type
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_num BSS number
+ * @param bss_type BSS type
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *
+wlan_get_priv_by_id(mlan_adapter * pmadapter, t_u32 bss_num, t_u32 bss_type)
+{
+ int i;
+
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (pmadapter->priv[i]) {
+ if ((pmadapter->priv[i]->bss_num == bss_num) &&
+ (pmadapter->priv[i]->bss_type == bss_type))
+ return (pmadapter->priv[i]);
+ }
+ }
+ return MNULL;
+}
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS role
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_role BSS role or MLAN_BSS_ROLE_ANY
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *
+wlan_get_priv(mlan_adapter * pmadapter, mlan_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (pmadapter->priv[i]) {
+ if (bss_role == MLAN_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(pmadapter->priv[i]) == bss_role)
+ return (pmadapter->priv[i]);
+ }
+ }
+ return MNULL;
+}
+
+/**
+ * @brief This function counts the number of occurences for a certain
+ * condition among privs. Which privs are checked can be configured
+ * via a second condition.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param count_cond Function pointer to condition to count on privs
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be counted or not. Use MNULL to check all privs.
+ *
+ * @return Count of privs where count_cond returned MTRUE.
+ */
+static int INLINE
+wlan_count_priv_cond(mlan_adapter * pmadapter,
+ t_bool(*count_cond) (IN pmlan_private pmpriv),
+ t_bool(*check_cond) (IN pmlan_private pmpriv))
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || count_cond == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if ((check_cond == MNULL) || (check_cond && check_cond(pmpriv))) {
+ if (count_cond(pmpriv))
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function runs a procedure on each priv.
+ * Which privs it is run on can be configured via a condition.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param operation Function pointer to produedure to operate on priv
+ * @param check_cond Function pointer to condition to decide whether priv
+ * operated on or not. Use MNULL to run on all privs.
+ *
+ * @return Number of privs that operation was run on.
+ */
+static int INLINE
+wlan_do_task_on_privs(mlan_adapter * pmadapter,
+ t_void(*operation) (IN pmlan_private pmpriv),
+ t_bool(*check_cond) (IN pmlan_private pmpriv))
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || operation == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if ((check_cond == MNULL) || (check_cond && check_cond(pmpriv))) {
+ operation(pmpriv);
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function builds a list of privs that test for a condition
+ * This is useful if you need to do a number of operations on the same set
+ * of privs. For one-off tasks, the above two functions might be better.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be placed in the list.
+ * @param ppriv_list Output param. Externally supplied array of mlan_private*
+ * to hold priv's that test positive with check_cond.
+ * Array size should be at least pmadapter->priv_num.
+ *
+ * @return Number of privs in ppriv_list
+ *
+ * @sa wlan_count_priv_cond
+ */
+static int INLINE
+wlan_get_privs_by_cond(mlan_adapter * pmadapter,
+ t_bool(*check_cond) (IN pmlan_private pmpriv),
+ mlan_private ** ppriv_list)
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || check_cond == MNULL || ppriv_list == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if (check_cond(pmpriv)) {
+ ppriv_list[count++] = pmpriv;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function builds a list of privs that test against two conditions
+ * This is useful if you need to do a number of operations on the same set
+ * of privs. Can choose whether both conditions (AND) or either condition (OR)
+ * is required.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be placed in the list.
+ * @param check_cond_2 Function pointer to second condition to check.
+ * @param and_conditions If MTRUE, both conditions must be met (AND),
+ * else either condition can be met (OR).
+ * @param ppriv_list Output param. Externally supplied array of mlan_private*
+ * to hold priv's that test positive with check_cond.
+ * Array size should be at least pmadapter->priv_num.
+ *
+ * @return Number of privs in ppriv_list
+ *
+ * @sa wlan_count_priv_cond, wlan_get_privs_by_cond
+ */
+static int INLINE
+wlan_get_privs_by_two_cond(mlan_adapter * pmadapter,
+ t_bool(*check_cond) (IN pmlan_private pmpriv),
+ t_bool(*check_cond_2) (IN pmlan_private pmpriv),
+ t_bool and_conditions, mlan_private ** ppriv_list)
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || check_cond == MNULL ||
+ check_cond_2 == MNULL || ppriv_list == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if (and_conditions) {
+ if (check_cond(pmpriv) && check_cond_2(pmpriv)) {
+ ppriv_list[count++] = pmpriv;
+ }
+ } else {
+ if (check_cond(pmpriv) || check_cond_2(pmpriv)) {
+ ppriv_list[count++] = pmpriv;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+#endif /* !_MLAN_MAIN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_meas.c b/drivers/net/wireless/sd8797/mlan/mlan_meas.c
new file mode 100644
index 000000000000..a2a6f2f5b8a1
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_meas.c
@@ -0,0 +1,464 @@
+/**
+ * @file mlan_meas.c
+ *
+ * @brief Implementation of measurement interface code with the app/firmware
+ *
+ * Driver implementation for sending and retrieving measurement requests
+ * and responses.
+ *
+ * Current use is limited to 802.11h.
+ *
+ * Requires use of the following preprocessor define:
+ * - ENABLE_MEAS
+ *
+ * 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/24/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_meas.h"
+
+/** Default measurement duration when not provided by the application */
+#define WLAN_MEAS_DEFAULT_MEAS_DURATION 1000U /* TUs */
+
+#ifdef DEBUG_LEVEL2
+/** String descriptions of the different measurement enums. Debug display */
+static const char *meas_type_str[WLAN_MEAS_NUM_TYPES] = {
+ "basic",
+};
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Retrieve the measurement string representation of a meas_type enum
+ * Used for debug display only
+ *
+ * @param meas_type Measurement type enumeration input for string lookup
+ *
+ * @return Constant string representing measurement type
+ */
+static const char *
+wlan_meas_get_meas_type_str(MeasType_t meas_type)
+{
+ if (meas_type <= WLAN_MEAS_11H_MAX_TYPE)
+ return meas_type_str[meas_type];
+
+ return "Invld";
+}
+#endif
+
+/**
+ * @brief Debug print display of the input measurement request
+ *
+ * @param pmeas_req Pointer to the measurement request to display
+ *
+ * @return N/A
+ */
+static void
+wlan_meas_dump_meas_req(const HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+
+ PRINTM(MINFO, "Meas: Req: mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmeas_req->mac_addr[0],
+ pmeas_req->mac_addr[1],
+ pmeas_req->mac_addr[2],
+ pmeas_req->mac_addr[3],
+ pmeas_req->mac_addr[4], pmeas_req->mac_addr[5]);
+
+ PRINTM(MINFO, "Meas: Req: dlgTkn: %d\n", pmeas_req->dialog_token);
+ PRINTM(MINFO, "Meas: Req: mode: dm[%c] rpt[%c] req[%c]\n",
+ pmeas_req->req_mode.duration_mandatory ? 'X' : ' ',
+ pmeas_req->req_mode.report ? 'X' : ' ',
+ pmeas_req->req_mode.request ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Req: : en[%c] par[%c]\n",
+ pmeas_req->req_mode.enable ? 'X' : ' ',
+ pmeas_req->req_mode.parallel ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Req: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_req->meas_type));
+#endif
+
+ switch (pmeas_req->meas_type) {
+ case WLAN_MEAS_BASIC:
+ /* Lazy cheat, fields of bas, cca, rpi union match on the request */
+ PRINTM(MINFO, "Meas: Req: chan: %u\n", pmeas_req->req.basic.channel);
+ PRINTM(MINFO, "Meas: Req: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_req->req.basic.start_time));
+ PRINTM(MINFO, "Meas: Req: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_req->req.basic.duration));
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Req: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief Debug print display of the input measurement report
+ *
+ * @param pmeas_rpt Pointer to measurement report to display
+ *
+ * @return N/A
+ */
+static void
+wlan_meas_dump_meas_rpt(const HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ PRINTM(MINFO, "Meas: Rpt: mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmeas_rpt->mac_addr[0],
+ pmeas_rpt->mac_addr[1],
+ pmeas_rpt->mac_addr[2],
+ pmeas_rpt->mac_addr[3],
+ pmeas_rpt->mac_addr[4], pmeas_rpt->mac_addr[5]);
+
+ PRINTM(MINFO, "Meas: Rpt: dlgTkn: %d\n", pmeas_rpt->dialog_token);
+
+ PRINTM(MINFO, "Meas: Rpt: rptMode: (%x): Rfs[%c] ICp[%c] Lt[%c]\n",
+ *(t_u8 *) & pmeas_rpt->rpt_mode,
+ pmeas_rpt->rpt_mode.refused ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.incapable ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.late ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Rpt: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_rpt->meas_type));
+#endif
+
+ switch (pmeas_rpt->meas_type) {
+ case WLAN_MEAS_BASIC:
+ PRINTM(MINFO, "Meas: Rpt: chan: %u\n", pmeas_rpt->rpt.basic.channel);
+ PRINTM(MINFO, "Meas: Rpt: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_rpt->rpt.basic.start_time));
+ PRINTM(MINFO, "Meas: Rpt: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_rpt->rpt.basic.duration));
+ PRINTM(MINFO, "Meas: Rpt: bas: (%x): unmsd[%c], radar[%c]\n",
+ *(t_u8 *) & (pmeas_rpt->rpt.basic.map),
+ pmeas_rpt->rpt.basic.map.unmeasured ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.radar ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Rpt: bas: unidSig[%c] ofdm[%c] bss[%c]\n",
+ pmeas_rpt->rpt.basic.map.unidentified_sig ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.ofdm_preamble ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.bss ? 'X' : ' ');
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Rpt: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * Callback from command processing when a measurement report is received
+ * from the firmware. Perform the following when a report is received:
+ *
+ * -# Debug displays the report if compiled with the appropriate flags
+ * -# If we are pending on a specific measurement report token, and it
+ * matches the received report's token, store the report and wake up
+ * any pending threads
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ * passing a HostCmd_DS_MEASUREMENT_REPORT structure.
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmdresp_get_report(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ const HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt = &resp->params.meas_rpt;
+
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: %#x-%u, Seq=%u, Ret=%u\n",
+ resp->command, resp->size, resp->seq_num, resp->result);
+
+ /* Debug displays the measurement report */
+ wlan_meas_dump_meas_rpt(pmeas_rpt);
+
+ /*
+ * Check if we are pending on a measurement report and it matches
+ * the dialog token of the received report:
+ */
+ if (pmadapter->state_meas.meas_rpt_pend_on
+ && pmadapter->state_meas.meas_rpt_pend_on == pmeas_rpt->dialog_token) {
+ PRINTM(MINFO, "Meas: Rpt: RCV'd Pend on meas #%d\n",
+ pmadapter->state_meas.meas_rpt_pend_on);
+
+ /* Clear the pending report indicator */
+ pmadapter->state_meas.meas_rpt_pend_on = 0;
+
+ /* Copy the received report into the measurement state for retrieval */
+ memcpy(pmadapter, &pmadapter->state_meas.meas_rpt_returned, pmeas_rpt,
+ sizeof(pmadapter->state_meas.meas_rpt_returned));
+
+ /*
+ * Wake up any threads pending on the wait queue
+ */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ }
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_MEASURMENT_REPORT firmware command
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_MEASUREMENT_REQUEST passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmd_request(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const void *pinfo_buf)
+{
+ const HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req =
+ (HostCmd_DS_MEASUREMENT_REQUEST *) pinfo_buf;
+
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REQUEST;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REQUEST) + S_DS_GEN;
+
+ memcpy(pmpriv->adapter, &pcmd_ptr->params.meas_req, pmeas_req,
+ sizeof(pcmd_ptr->params.meas_req));
+
+ PRINTM(MINFO, "Meas: Req: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+
+ wlan_meas_dump_meas_req(pmeas_req);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * The firmware will send a EVENT_MEAS_REPORT_RDY event when it
+ * completes or receives a measurement report. The event response
+ * handler will then start a HostCmd_CMD_MEASUREMENT_REPORT firmware command
+ * which gets completed for transmission to the firmware in this routine.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmd_get_report(mlan_private * pmpriv, HostCmd_DS_COMMAND * pcmd_ptr)
+{
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REPORT;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REPORT) + S_DS_GEN;
+
+ memset(pmpriv->adapter, &pcmd_ptr->params.meas_rpt, 0x00,
+ sizeof(pcmd_ptr->params.meas_rpt));
+
+ /*
+ * Set the meas_rpt.mac_addr to our mac address to get a meas report,
+ * setting the mac to another STA address instructs the firmware
+ * to transmit this measurement report frame instead
+ */
+ memcpy(pmpriv->adapter, pcmd_ptr->params.meas_rpt.mac_addr,
+ pmpriv->curr_addr, sizeof(pcmd_ptr->params.meas_rpt.mac_addr));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief Send the input measurement request to the firmware.
+ *
+ * If the dialog token in the measurement request is set to 0, the function
+ * will use an local static auto-incremented token in the measurement
+ * request. This ensures the dialog token is always set.
+ *
+ * If wait_for_resp_timeout is set, the function will block its return on
+ * a timeout or returned measurement report that matches the requests
+ * dialog token.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pmeas_req Pointer to the measurement request to send
+ * @param wait_for_resp_timeout Timeout value of the measurement request
+ * in ms.
+ * @param pioctl_req Pointer to IOCTL request buffer
+ * @param pmeas_rpt Output parameter: Pointer for the resulting
+ * measurement report
+ *
+ * @return
+ * - 0 for success
+ * - -ETIMEDOUT if the measurement report does not return before
+ * the timeout expires
+ * - Error return from wlan_prepare_cmd routine otherwise
+ */
+int
+wlan_meas_util_send_req(mlan_private * pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req,
+ t_u32 wait_for_resp_timeout, pmlan_ioctl_req pioctl_req,
+ HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt)
+{
+ static t_u8 auto_dialog_tok = 0;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ int ret;
+
+ ENTER();
+
+ /* If dialogTok was set to 0 or not provided, autoset */
+ pmeas_req->dialog_token = (pmeas_req->dialog_token ?
+ pmeas_req->dialog_token : ++auto_dialog_tok);
+
+ /* Check for rollover of the dialog token. Avoid using 0 as a token */
+ pmeas_req->dialog_token = (pmeas_req->dialog_token ?
+ pmeas_req->dialog_token : 1);
+
+ /*
+ * If the request is to pend waiting for the result, set the dialog token
+ * of this measurement request in the state structure. The measurement
+ * report handling routines can then check the incoming measurement
+ * reports for a match with this dialog token.
+ */
+ if (wait_for_resp_timeout) {
+ pmeas_state->meas_rpt_pend_on = pmeas_req->dialog_token;
+ PRINTM(MINFO, "Meas: Req: START Pend on meas #%d\n",
+ pmeas_req->dialog_token);
+ }
+
+ /* Send the measurement request to the firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEASUREMENT_REQUEST,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, (void *) pmeas_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare the HostCmd_DS_Command structure for a measurement 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_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer passthrough with data necessary for a
+ * specific command type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+int
+wlan_meas_cmd_process(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const void *pinfo_buf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ ret = wlan_meas_cmd_request(pmpriv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_get_report(pmpriv, pcmd_ptr);
+ 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 for a measurement
+ * command
+ *
+ * Use the Command field to determine if the command response being
+ * is for meas. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_802_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_meas_cmdresp_process(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ PRINTM(MINFO, "Meas: Req Resp: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_get_report(pmpriv, resp);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_meas.h b/drivers/net/wireless/sd8797/mlan/mlan_meas.h
new file mode 100644
index 000000000000..0eb51d3a3bb2
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_meas.h
@@ -0,0 +1,54 @@
+/**
+ * @file mlan_meas.h
+ *
+ * @brief Interface for the measurement module implemented in mlan_meas.c
+ *
+ * Driver interface functions and type declarations for the measurement module
+ * implemented in mlan_meas.c
+ *
+ * @sa mlan_meas.c
+ *
+ * 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/25/2009: initial version
+************************************************************/
+
+#ifndef _MLAN_MEAS_H_
+#define _MLAN_MEAS_H_
+
+#include "mlan_fw.h"
+
+/* Send a given measurement request to the firmware, report back the result */
+extern int
+wlan_meas_util_send_req(mlan_private * pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req,
+ t_u32 wait_for_resp_timeout, pmlan_ioctl_req pioctl_req,
+ HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt);
+
+/* Setup a measurement command before it is sent to the firmware */
+extern int wlan_meas_cmd_process(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf);
+
+/* Handle a given measurement command response from the firmware */
+extern int wlan_meas_cmdresp_process(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp);
+
+#endif /* _MLAN_MEAS_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_misc.c b/drivers/net/wireless/sd8797/mlan/mlan_misc.c
new file mode 100644
index 000000000000..f41dcea3d206
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_misc.c
@@ -0,0 +1,2156 @@
+/**
+ * @file mlan_misc.c
+ *
+ * @brief This file include miscellaneous functions for MLAN module
+ *
+ * Copyright (C) 2009-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:
+ 05/11/2009: initial version
+************************************************************/
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif /* STA_SUPPORT */
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+extern mlan_operations *mlan_ops[];
+#endif
+extern t_u8 ac_to_tid[4][2];
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/** Custom IE auto index and mask */
+#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
+/** Custom IE mask for delete operation */
+#define MLAN_CUSTOM_IE_DELETE_MASK 0
+/** Custom IE header size */
+#define MLAN_CUSTOM_IE_HDR_SIZE (sizeof(custom_ie)-MAX_IE_SIZE)
+
+/**
+ * @brief Check if current custom IE index is used on other interfaces.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param idx index to check for in use
+ *
+ * @return MLAN_STATUS_SUCCESS --unused, otherwise used.
+ */
+static mlan_status
+wlan_is_custom_ie_index_unused(IN pmlan_private pmpriv, IN t_u16 idx)
+{
+ t_u8 i = 0;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_private priv;
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ priv = pmadapter->priv[i];
+ /* Check for other interfaces only */
+ if (priv && priv->bss_index != pmpriv->bss_index) {
+
+ if (priv->mgmt_ie[idx].mgmt_subtype_mask &&
+ priv->mgmt_ie[idx].ie_length) {
+ /* used entry found */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get the custom IE index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param mask mask value for which the index to be returned
+ * @param ie_data a pointer to custom_ie structure
+ * @param idx will hold the computed index
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_custom_ioctl_get_autoidx(IN pmlan_private pmpriv,
+ IN pmlan_ioctl_req pioctl_req,
+ IN t_u16 mask,
+ IN custom_ie * ie_data, OUT t_u16 * idx)
+{
+ t_u16 index = 0, insert = MFALSE;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Determine the index where the IE needs to be inserted */
+ while (!insert) {
+ while (index < pmpriv->adapter->max_mgmt_ie_index) {
+ if (pmpriv->mgmt_ie[index].mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ index++;
+ continue;
+ }
+ if (pmpriv->mgmt_ie[index].mgmt_subtype_mask == mask) {
+ /* Duplicate IE should be avoided */
+ if (pmpriv->mgmt_ie[index].ie_length) {
+ if (!memcmp
+ (pmpriv->adapter, pmpriv->mgmt_ie[index].ie_buffer,
+ ie_data->ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length)) {
+ PRINTM(MERROR,
+ "IE with the same mask exists at index %d\n",
+ index);
+ *idx = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ goto done;
+ }
+ }
+ /* Check if enough space is available */
+ if (pmpriv->mgmt_ie[index].ie_length + ie_data->ie_length >
+ MAX_IE_SIZE) {
+ index++;
+ continue;
+ }
+ insert = MTRUE;
+ break;
+ }
+ index++;
+ }
+ if (!insert) {
+ for (index = 0; index < pmpriv->adapter->max_mgmt_ie_index; index++) {
+ if (pmpriv->mgmt_ie[index].ie_length == 0) {
+ /*
+ * Check if this index is in use by other interface
+ * If yes, move ahead to next index
+ */
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_is_custom_ie_index_unused(pmpriv, index)) {
+ insert = MTRUE;
+ break;
+ } else {
+ PRINTM(MINFO, "Skipping IE index %d in use.\n", index);
+ }
+ }
+ }
+ }
+ if (index == pmpriv->adapter->max_mgmt_ie_index && !insert) {
+ PRINTM(MERROR, "Failed to Set the IE buffer\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ *idx = index;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Delete custom IE
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ie_data a pointer to custom_ie structure
+ * @param idx index supplied
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+
+static mlan_status
+wlan_custom_ioctl_auto_delete(IN pmlan_private pmpriv,
+ IN pmlan_ioctl_req pioctl_req,
+ IN custom_ie * ie_data, IN t_u16 idx)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u16 index = 0, insert = MFALSE, del_len;
+ t_u8 del_ie[MAX_IE_SIZE], ie[MAX_IE_SIZE];
+ t_s32 cnt, tmp_len = 0;
+ t_u8 *tmp_ie;
+
+ ENTER();
+ memset(pmpriv->adapter, del_ie, 0, MAX_IE_SIZE);
+ memcpy(pmpriv->adapter, del_ie, ie_data->ie_buffer,
+ MIN(MAX_IE_SIZE, ie_data->ie_length));
+ del_len = MIN(MAX_IE_SIZE, ie_data->ie_length);
+
+ for (index = 0; index < pmadapter->max_mgmt_ie_index; index++) {
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx)
+ index = idx;
+ tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
+ tmp_len = pmpriv->mgmt_ie[index].ie_length;
+ cnt = 0;
+ while (tmp_len) {
+ if (!memcmp(pmpriv->adapter, tmp_ie, del_ie, del_len)) {
+ memcpy(pmpriv->adapter, ie, pmpriv->mgmt_ie[index].ie_buffer,
+ cnt);
+ if (pmpriv->mgmt_ie[index].ie_length > (cnt + del_len))
+ memcpy(pmpriv->adapter, &ie[cnt],
+ &pmpriv->mgmt_ie[index].ie_buffer[cnt + del_len],
+ (pmpriv->mgmt_ie[index].ie_length -
+ (cnt + del_len)));
+ memset(pmpriv->adapter, &pmpriv->mgmt_ie[index].ie_buffer, 0,
+ sizeof(pmpriv->mgmt_ie[index].ie_buffer));
+ memcpy(pmpriv->adapter, &pmpriv->mgmt_ie[index].ie_buffer, ie,
+ pmpriv->mgmt_ie[index].ie_length - del_len);
+ pmpriv->mgmt_ie[index].ie_length -= del_len;
+ insert = MTRUE;
+ tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
+ tmp_len = pmpriv->mgmt_ie[index].ie_length;
+ cnt = 0;
+ continue;
+ }
+ tmp_ie++;
+ tmp_len--;
+ cnt++;
+ }
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx)
+ break;
+ }
+ if (index == pmadapter->max_mgmt_ie_index && !insert) {
+ PRINTM(MERROR, "Failed to Clear IE buffer\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief send host cmd
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_host_cmd(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_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0,
+ 0,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function init/shutdown command to firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_init_shutdown(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd;
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_INIT)
+ cmd = HostCmd_CMD_FUNC_INIT;
+ else if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_SHUTDOWN)
+ cmd = HostCmd_CMD_FUNC_SHUTDOWN;
+ else {
+ PRINTM(MERROR, "Unsupported parameter\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get debug information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status
+wlan_get_info_debug_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ t_u8 *ptid;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ pmadapter->max_tx_buf_size =
+ (t_u16) info->param.debug_info.max_tx_buf_size;
+ pmadapter->tx_buf_size = (t_u16) info->param.debug_info.tx_buf_size;
+ pmadapter->curr_tx_buf_size =
+ (t_u16) info->param.debug_info.curr_tx_buf_size;
+ pmadapter->ps_mode = info->param.debug_info.ps_mode;
+ pmadapter->ps_state = info->param.debug_info.ps_state;
+#ifdef STA_SUPPORT
+ pmadapter->is_deep_sleep = info->param.debug_info.is_deep_sleep;
+#endif /* STA_SUPPORT */
+ pmadapter->pm_wakeup_card_req =
+ info->param.debug_info.pm_wakeup_card_req;
+ pmadapter->pm_wakeup_fw_try = info->param.debug_info.pm_wakeup_fw_try;
+ pmadapter->is_hs_configured = info->param.debug_info.is_hs_configured;
+ pmadapter->hs_activated = info->param.debug_info.hs_activated;
+ pmadapter->pps_uapsd_mode = info->param.debug_info.pps_uapsd_mode;
+ pmadapter->sleep_period.period = info->param.debug_info.sleep_pd;
+ pmpriv->wmm_qosinfo = info->param.debug_info.qos_cfg;
+ pmadapter->tx_lock_flag = info->param.debug_info.tx_lock_flag;
+ pmpriv->port_open = info->param.debug_info.port_open;
+ pmadapter->scan_processing = info->param.debug_info.scan_processing;
+
+ pmadapter->dbg.num_cmd_host_to_card_failure =
+ info->param.debug_info.num_cmd_host_to_card_failure;
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure =
+ info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure;
+ pmadapter->dbg.num_tx_host_to_card_failure =
+ info->param.debug_info.num_tx_host_to_card_failure;
+ pmadapter->dbg.num_cmdevt_card_to_host_failure =
+ info->param.debug_info.num_cmdevt_card_to_host_failure;
+ pmadapter->dbg.num_rx_card_to_host_failure =
+ info->param.debug_info.num_rx_card_to_host_failure;
+ pmadapter->dbg.num_int_read_failure =
+ info->param.debug_info.num_int_read_failure;
+ pmadapter->dbg.last_int_status = info->param.debug_info.last_int_status;
+ pmadapter->dbg.num_event_deauth =
+ info->param.debug_info.num_event_deauth;
+ pmadapter->dbg.num_event_disassoc =
+ info->param.debug_info.num_event_disassoc;
+ pmadapter->dbg.num_event_link_lost =
+ info->param.debug_info.num_event_link_lost;
+ pmadapter->dbg.num_cmd_deauth = info->param.debug_info.num_cmd_deauth;
+ pmadapter->dbg.num_cmd_assoc_success =
+ info->param.debug_info.num_cmd_assoc_success;
+ pmadapter->dbg.num_cmd_assoc_failure =
+ info->param.debug_info.num_cmd_assoc_failure;
+ pmadapter->dbg.num_tx_timeout = info->param.debug_info.num_tx_timeout;
+ pmadapter->dbg.num_cmd_timeout = info->param.debug_info.num_cmd_timeout;
+ pmadapter->dbg.timeout_cmd_id = info->param.debug_info.timeout_cmd_id;
+ pmadapter->dbg.timeout_cmd_act = info->param.debug_info.timeout_cmd_act;
+ memcpy(pmadapter, pmadapter->dbg.last_cmd_id,
+ info->param.debug_info.last_cmd_id,
+ sizeof(pmadapter->dbg.last_cmd_id));
+ memcpy(pmadapter, pmadapter->dbg.last_cmd_act,
+ info->param.debug_info.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act));
+ pmadapter->dbg.last_cmd_index = info->param.debug_info.last_cmd_index;
+ memcpy(pmadapter, pmadapter->dbg.last_cmd_resp_id,
+ info->param.debug_info.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id));
+ pmadapter->dbg.last_cmd_resp_index =
+ info->param.debug_info.last_cmd_resp_index;
+ memcpy(pmadapter, pmadapter->dbg.last_event,
+ info->param.debug_info.last_event,
+ sizeof(pmadapter->dbg.last_event));
+ pmadapter->dbg.last_event_index =
+ info->param.debug_info.last_event_index;
+
+ pmadapter->data_sent = info->param.debug_info.data_sent;
+ pmadapter->cmd_sent = info->param.debug_info.cmd_sent;
+ pmadapter->mp_rd_bitmap = info->param.debug_info.mp_rd_bitmap;
+ pmadapter->mp_wr_bitmap = info->param.debug_info.mp_wr_bitmap;
+ pmadapter->curr_rd_port = info->param.debug_info.curr_rd_port;
+ pmadapter->curr_wr_port = info->param.debug_info.curr_wr_port;
+ pmadapter->cmd_resp_received = info->param.debug_info.cmd_resp_received;
+#ifdef UAP_SUPPORT
+ pmadapter->pending_bridge_pkts = info->param.debug_info.num_bridge_pkts;
+ pmpriv->num_drop_pkts = info->param.debug_info.num_drop_pkts;
+#endif
+ } else { /* MLAN_ACT_GET */
+ ptid = ac_to_tid[WMM_AC_BK];
+ info->param.debug_info.wmm_ac_bk =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_BE];
+ info->param.debug_info.wmm_ac_be =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_VI];
+ info->param.debug_info.wmm_ac_vi =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_VO];
+ info->param.debug_info.wmm_ac_vo =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ info->param.debug_info.max_tx_buf_size =
+ (t_u32) pmadapter->max_tx_buf_size;
+ info->param.debug_info.tx_buf_size = (t_u32) pmadapter->tx_buf_size;
+ info->param.debug_info.curr_tx_buf_size =
+ (t_u32) pmadapter->curr_tx_buf_size;
+ info->param.debug_info.rx_tbl_num =
+ wlan_get_rxreorder_tbl(pmpriv, info->param.debug_info.rx_tbl);
+ info->param.debug_info.tx_tbl_num =
+ wlan_get_txbastream_tbl(pmpriv, info->param.debug_info.tx_tbl);
+ info->param.debug_info.ps_mode = pmadapter->ps_mode;
+ info->param.debug_info.ps_state = pmadapter->ps_state;
+#ifdef STA_SUPPORT
+ info->param.debug_info.is_deep_sleep = pmadapter->is_deep_sleep;
+#endif /* STA_SUPPORT */
+ info->param.debug_info.pm_wakeup_card_req =
+ pmadapter->pm_wakeup_card_req;
+ info->param.debug_info.pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try;
+ info->param.debug_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.debug_info.hs_activated = pmadapter->hs_activated;
+ info->param.debug_info.pps_uapsd_mode = pmadapter->pps_uapsd_mode;
+ info->param.debug_info.sleep_pd = pmadapter->sleep_period.period;
+ info->param.debug_info.qos_cfg = pmpriv->wmm_qosinfo;
+ info->param.debug_info.tx_lock_flag = pmadapter->tx_lock_flag;
+ info->param.debug_info.port_open = pmpriv->port_open;
+ info->param.debug_info.scan_processing = pmadapter->scan_processing;
+
+ info->param.debug_info.num_cmd_host_to_card_failure
+ = pmadapter->dbg.num_cmd_host_to_card_failure;
+ info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure
+ = pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
+ info->param.debug_info.num_tx_host_to_card_failure
+ = pmadapter->dbg.num_tx_host_to_card_failure;
+ info->param.debug_info.num_cmdevt_card_to_host_failure
+ = pmadapter->dbg.num_cmdevt_card_to_host_failure;
+ info->param.debug_info.num_rx_card_to_host_failure
+ = pmadapter->dbg.num_rx_card_to_host_failure;
+ info->param.debug_info.num_int_read_failure =
+ pmadapter->dbg.num_int_read_failure;
+ info->param.debug_info.last_int_status = pmadapter->dbg.last_int_status;
+ info->param.debug_info.num_event_deauth =
+ pmadapter->dbg.num_event_deauth;
+ info->param.debug_info.num_event_disassoc =
+ pmadapter->dbg.num_event_disassoc;
+ info->param.debug_info.num_event_link_lost =
+ pmadapter->dbg.num_event_link_lost;
+ info->param.debug_info.num_cmd_deauth = pmadapter->dbg.num_cmd_deauth;
+ info->param.debug_info.num_cmd_assoc_success =
+ pmadapter->dbg.num_cmd_assoc_success;
+ info->param.debug_info.num_cmd_assoc_failure =
+ pmadapter->dbg.num_cmd_assoc_failure;
+ info->param.debug_info.num_tx_timeout = pmadapter->dbg.num_tx_timeout;
+ info->param.debug_info.num_cmd_timeout = pmadapter->dbg.num_cmd_timeout;
+ info->param.debug_info.timeout_cmd_id = pmadapter->dbg.timeout_cmd_id;
+ info->param.debug_info.timeout_cmd_act = pmadapter->dbg.timeout_cmd_act;
+ memcpy(pmadapter, info->param.debug_info.last_cmd_id,
+ pmadapter->dbg.last_cmd_id, sizeof(pmadapter->dbg.last_cmd_id));
+ memcpy(pmadapter, info->param.debug_info.last_cmd_act,
+ pmadapter->dbg.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act));
+ info->param.debug_info.last_cmd_index = pmadapter->dbg.last_cmd_index;
+ memcpy(pmadapter, info->param.debug_info.last_cmd_resp_id,
+ pmadapter->dbg.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id));
+ info->param.debug_info.last_cmd_resp_index =
+ pmadapter->dbg.last_cmd_resp_index;
+ memcpy(pmadapter, info->param.debug_info.last_event,
+ pmadapter->dbg.last_event, sizeof(pmadapter->dbg.last_event));
+ info->param.debug_info.last_event_index =
+ pmadapter->dbg.last_event_index;
+
+ info->param.debug_info.mp_rd_bitmap = pmadapter->mp_rd_bitmap;
+ info->param.debug_info.mp_wr_bitmap = pmadapter->mp_wr_bitmap;
+ info->param.debug_info.curr_rd_port = pmadapter->curr_rd_port;
+ info->param.debug_info.curr_wr_port = pmadapter->curr_wr_port;
+ info->param.debug_info.data_sent = pmadapter->data_sent;
+ info->param.debug_info.cmd_sent = pmadapter->cmd_sent;
+ info->param.debug_info.cmd_resp_received = pmadapter->cmd_resp_received;
+ info->param.debug_info.tx_pkts_queued =
+ util_scalar_read(pmadapter->pmoal_handle,
+ &pmpriv->wmm.tx_pkts_queued, MNULL, MNULL);
+#ifdef UAP_SUPPORT
+ info->param.debug_info.num_bridge_pkts = pmadapter->pending_bridge_pkts;
+ info->param.debug_info.num_drop_pkts = pmpriv->num_drop_pkts;
+#endif
+ }
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function wakes up the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_pm_wakeup_card(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ PRINTM(MEVENT, "Wakeup device...\n");
+ ret =
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG,
+ HOST_POWER_UP);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function resets the PM setting of the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_pm_reset_card(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ ret =
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG, 0);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get HS configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_pm_ioctl_hscfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 prev_cond = 0;
+
+ ENTER();
+
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+#ifdef STA_SUPPORT
+ if (pmadapter->pps_uapsd_mode) {
+ PRINTM(MINFO, "Host Sleep IOCTL is blocked in UAPSD/PPS mode\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+#endif /* STA_SUPPORT */
+ if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) {
+ if (pm->param.hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL) {
+ if (pmadapter->is_hs_configured == MFALSE) {
+ /* Already cancelled */
+ break;
+ }
+ /* Save previous condition */
+ prev_cond = pmadapter->hs_cfg.conditions;
+ pmadapter->hs_cfg.conditions = pm->param.hs_cfg.conditions;
+ } else if (pmadapter->hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL) {
+ /* Return failure if no parameters for HS enable */
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req,
+ (t_void *) (&pmadapter->hs_cfg));
+ if (status == MLAN_STATUS_SUCCESS)
+ status = MLAN_STATUS_PENDING;
+ if (pm->param.hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL) {
+ /* Restore previous condition */
+ pmadapter->hs_cfg.conditions = prev_cond;
+ }
+ } else {
+ pmadapter->hs_cfg.conditions = pm->param.hs_cfg.conditions;
+ pmadapter->hs_cfg.gpio = (t_u8) pm->param.hs_cfg.gpio;
+ pmadapter->hs_cfg.gap = (t_u8) pm->param.hs_cfg.gap;
+ }
+ break;
+ case MLAN_ACT_GET:
+ pm->param.hs_cfg.conditions = pmadapter->hs_cfg.conditions;
+ pm->param.hs_cfg.gpio = pmadapter->hs_cfg.gpio;
+ pm->param.hs_cfg.gap = pmadapter->hs_cfg.gap;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function allocates a mlan_buffer.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param data_len Data length
+ * @param head_room head_room reserved in mlan_buffer
+ * @param malloc_flag flag to user moal_malloc
+ * @return mlan_buffer pointer or MNULL
+ */
+pmlan_buffer
+wlan_alloc_mlan_buffer(mlan_adapter * pmadapter, t_u32 data_len,
+ t_u32 head_room, t_u32 malloc_flag)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = MNULL;
+ t_u32 buf_size = 0;
+ t_u8 *tmp_buf = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* make sure that the data length is at least SDIO block size */
+ data_len = ALIGN_SZ(data_len, MLAN_SDIO_BLOCK_SIZE);
+
+ /* head_room is not implemented for malloc mlan buffer */
+ if (malloc_flag == MTRUE) {
+ buf_size = sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ pmbuf = MNULL;
+ goto exit;
+ }
+ memset(pmadapter, pmbuf, 0, sizeof(mlan_buffer));
+
+ pmbuf->pdesc = MNULL;
+ /* Align address */
+ pmbuf->pbuf =
+ (t_u8 *) ALIGN_ADDR((t_u8 *) pmbuf + sizeof(mlan_buffer),
+ DMA_ALIGNMENT);
+ pmbuf->data_offset = 0;
+ pmbuf->data_len = data_len;
+ pmbuf->flags |= MLAN_BUF_FLAG_MALLOC_BUF;
+ } else {
+ /* use moal_alloc_mlan_buffer, head_room supported */
+ ret = pcb->moal_alloc_mlan_buffer(pmadapter->pmoal_handle,
+ data_len + DMA_ALIGNMENT + head_room,
+ &pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
+ goto exit;
+ }
+ pmbuf->data_offset = head_room;
+ tmp_buf =
+ (t_u8 *) ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset,
+ DMA_ALIGNMENT);
+ pmbuf->data_offset +=
+ (t_u32) (tmp_buf - (pmbuf->pbuf + pmbuf->data_offset));
+ pmbuf->data_len = data_len;
+ pmbuf->flags = 0;
+ }
+ exit:
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function frees a mlan_buffer.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_mlan_buffer(mlan_adapter * pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+
+ if (pcb && pmbuf) {
+ if (pmbuf->flags & MLAN_BUF_FLAG_MALLOC_BUF)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmbuf);
+ else
+ pcb->moal_free_mlan_buffer(pmadapter->pmoal_handle, pmbuf);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Delay function implementation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param delay Delay value
+ * @param u Units of delay (sec, msec or usec)
+ *
+ * @return N/A
+ */
+t_void
+wlan_delay_func(mlan_adapter * pmadapter, t_u32 delay, t_delay_unit u)
+{
+ t_u32 now_tv_sec, now_tv_usec;
+ t_u32 upto_tv_sec, upto_tv_usec;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pcb->moal_udelay) {
+ if (u == SEC) {
+ delay *= 1000000;
+ } else if (u == MSEC) {
+ delay *= 1000;
+ }
+ pcb->moal_udelay(pmadapter->pmoal_handle, delay);
+ } else {
+
+ pcb->moal_get_system_time(pmadapter->pmoal_handle, &upto_tv_sec,
+ &upto_tv_usec);
+
+ switch (u) {
+ case SEC:
+ upto_tv_sec += delay;
+ break;
+ case MSEC:
+ delay *= 1000;
+ case USEC:
+ upto_tv_sec += (delay / 1000000);
+ upto_tv_usec += (delay % 1000000);
+ break;
+ }
+
+ do {
+ pcb->moal_get_system_time(pmadapter->pmoal_handle, &now_tv_sec,
+ &now_tv_usec);
+ if (now_tv_sec > upto_tv_sec) {
+ LEAVE();
+ return;
+ }
+
+ if ((now_tv_sec == upto_tv_sec) && (now_tv_usec >= upto_tv_usec)) {
+ LEAVE();
+ return;
+ }
+ } while (MTRUE);
+ }
+
+ LEAVE();
+ return;
+}
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, MLAN_STATUS_PENDING --pending
+ */
+mlan_status
+wlan_bss_ioctl_bss_role(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_VERSION_EXT dummy;
+#if defined(WIFI_DIRECT_SUPPORT)
+ t_u8 bss_mode;
+#endif
+ t_u8 i, global_band = 0;
+ int j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_role = GET_BSS_ROLE(pmpriv);
+ } else {
+ /** Switch BSS role */
+ wlan_free_priv(pmpriv);
+
+ pmpriv->bss_role = bss->param.bss_role;
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_UAP)
+ pmpriv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (pmpriv->bss_type == MLAN_BSS_TYPE_STA)
+ pmpriv->bss_type = MLAN_BSS_TYPE_UAP;
+
+ /* Initialize private structures */
+ wlan_init_priv(pmpriv);
+
+ /* Initialize function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmpriv)) {
+ memcpy(pmadapter, &pmpriv->ops, mlan_ops[j],
+ sizeof(mlan_operations));
+ }
+ }
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i] &&
+ GET_BSS_ROLE(pmadapter->priv[i]) == MLAN_BSS_ROLE_STA)
+ global_band |= pmadapter->priv[i]->config_bands;
+ }
+
+ if (global_band != pmadapter->config_bands) {
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ global_band | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_11d_set_universaltable
+ (pmpriv, global_band | pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->config_bands = global_band;
+ }
+
+ /* Issue commands to initialize firmware */
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ bss_mode = BSS_MODE_WIFIDIRECT_CLIENT;
+ else
+ bss_mode = BSS_MODE_WIFIDIRECT_GO;
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &bss_mode);
+#endif
+ pmpriv->ops.init_cmd(pmpriv, MFALSE);
+
+ /* Issue dummy Get command to complete the ioctl */
+ memset(pmadapter, &dummy, 0, sizeof(HostCmd_DS_VERSION_EXT));
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, (t_void *) & dummy);
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set the custom IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param send_ioctl Flag to indicate if ioctl should be sent with cmd
+ * (MTRUE if from moal/user, MFALSE if internal)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_custom_ie_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req,
+ IN t_bool send_ioctl)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ custom_ie *ie_data = MNULL;
+ t_u16 cmd_action = 0, index, mask, i, len, app_data_len, ioctl_len;
+ t_u8 *tmp_ie;
+
+ ENTER();
+
+ if ((misc->param.cust_ie.len == 0) ||
+ (misc->param.cust_ie.len == sizeof(t_u16))) {
+ pioctl_req->action = MLAN_ACT_GET;
+ /* Get the IE */
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ /* ioctl_len : ioctl length from application, start with
+ misc->param.cust_ie.len and reach upto 0 */
+ ioctl_len = misc->param.cust_ie.len;
+
+ /* app_data_len : length from application, start with 0 and reach upto
+ ioctl_len */
+ app_data_len = sizeof(MrvlIEtypesHeader_t);
+ misc->param.cust_ie.len = 0;
+
+ while (ioctl_len > 0) {
+ ie_data = (custom_ie *) (((t_u8 *) & misc->param.cust_ie)
+ + app_data_len);
+ ioctl_len -= (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
+ app_data_len += (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
+
+ index = ie_data->ie_index;
+ mask = ie_data->mgmt_subtype_mask;
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) { /* Need to be
+ Autohandled */
+ if (mask == MLAN_CUSTOM_IE_DELETE_MASK) { /* Automatic
+ Deletion */
+ ret =
+ wlan_custom_ioctl_auto_delete(pmpriv, pioctl_req,
+ ie_data, index);
+ /* if IE to delete is not found, return error */
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ }
+ memset(pmadapter, ie_data, 0,
+ sizeof(custom_ie) * MAX_MGMT_IE_INDEX_TO_FW);
+ len = 0;
+ for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) {
+ memcpy(pmadapter, (t_u8 *) ie_data + len, &i,
+ sizeof(ie_data->ie_index));
+ len += sizeof(ie_data->ie_index);
+ memcpy(pmadapter, (t_u8 *) ie_data + len,
+ &pmpriv->mgmt_ie[i].mgmt_subtype_mask,
+ sizeof(ie_data->mgmt_subtype_mask));
+ len += sizeof(ie_data->mgmt_subtype_mask);
+ memcpy(pmadapter, (t_u8 *) ie_data + len,
+ &pmpriv->mgmt_ie[i].ie_length,
+ sizeof(ie_data->ie_length));
+ len += sizeof(ie_data->ie_length);
+ if (pmpriv->mgmt_ie[i].ie_length) {
+ memcpy(pmadapter, (t_u8 *) ie_data + len,
+ &pmpriv->mgmt_ie[i].ie_buffer,
+ pmpriv->mgmt_ie[i].ie_length);
+ len += pmpriv->mgmt_ie[i].ie_length;
+ }
+ }
+ misc->param.cust_ie.len += len;
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else { /* Automatic Addition */
+ if (MLAN_STATUS_FAILURE ==
+ wlan_custom_ioctl_get_autoidx(pmpriv, pioctl_req, mask,
+ ie_data, &index)) {
+ PRINTM(MERROR, "Failed to Set the IE buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ tmp_ie = (t_u8 *) & pmpriv->mgmt_ie[index].ie_buffer;
+ memcpy(pmadapter, tmp_ie + pmpriv->mgmt_ie[index].ie_length,
+ &ie_data->ie_buffer, ie_data->ie_length);
+ pmpriv->mgmt_ie[index].ie_length += ie_data->ie_length;
+ pmpriv->mgmt_ie[index].ie_index = index;
+ pmpriv->mgmt_ie[index].mgmt_subtype_mask = mask;
+
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ ie_data->ie_index = index;
+ ie_data->ie_length = pmpriv->mgmt_ie[index].ie_length;
+ memcpy(pmadapter, &ie_data->ie_buffer,
+ &pmpriv->mgmt_ie[index].ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length);
+ misc->param.cust_ie.len +=
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ }
+ } else {
+ if (index >= pmadapter->max_mgmt_ie_index) {
+ PRINTM(MERROR, "Invalid custom IE index %d\n", index);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Set/Clear the IE and save it */
+ if (ie_data->mgmt_subtype_mask == MLAN_CUSTOM_IE_DELETE_MASK &&
+ ie_data->ie_length) {
+ PRINTM(MINFO, "Clear the IE buffer\n");
+ ret =
+ wlan_custom_ioctl_auto_delete(pmpriv, pioctl_req,
+ ie_data, index);
+ /* if IE to delete is not found, return error */
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ }
+ memset(pmadapter, ie_data, 0,
+ sizeof(custom_ie) * MAX_MGMT_IE_INDEX_TO_FW);
+ memcpy(pmadapter, (t_u8 *) ie_data, &pmpriv->mgmt_ie[index],
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE);
+ } else {
+ /*
+ * Check if this index is being used on any other
+ * interfaces. If yes, then the request needs to be rejected.
+ */
+ ret = wlan_is_custom_ie_index_unused(pmpriv, index);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "IE index is used by other interface.\n");
+ PRINTM(MERROR,
+ "Set or delete on index %d is not allowed.\n",
+ index);
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ goto done;
+ }
+ PRINTM(MINFO, "Set the IE buffer\n");
+ if (ie_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK)
+ ie_data->ie_length = 0;
+ else {
+ if ((pmpriv->mgmt_ie[index].ie_length ==
+ ie_data->ie_length) &&
+ !memcmp(pmpriv->adapter,
+ pmpriv->mgmt_ie[index].ie_buffer,
+ ie_data->ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length)) {
+ PRINTM(MIOCTL,
+ "same customer ie already configured!\n");
+ goto done;
+ }
+ }
+ memset(pmadapter, &pmpriv->mgmt_ie[index], 0,
+ sizeof(custom_ie));
+ memcpy(pmadapter, &pmpriv->mgmt_ie[index], ie_data,
+ sizeof(custom_ie));
+ }
+
+ misc->param.cust_ie.len += pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+ }
+ }
+
+ /* Send command to firmware */
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MGMT_IE_LIST,
+ cmd_action,
+ 0,
+ (send_ioctl) ? (t_void *) pioctl_req : MNULL,
+ &misc->param.cust_ie);
+ }
+#ifdef UAP_SUPPORT
+ else if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_SYS_CONFIGURE,
+ cmd_action,
+ 0,
+ (send_ioctl) ? (t_void *) pioctl_req : MNULL,
+ (send_ioctl) ? MNULL : &misc->param.cust_ie);
+ }
+#endif
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will check if station list is empty
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MFALSE/MTRUE
+ */
+t_u8
+wlan_is_station_list_empty(mlan_private * priv)
+{
+ ENTER();
+ if (!(util_peek_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ LEAVE();
+ return MTRUE;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will return the pointer to station entry in station list
+ * table which matches the give mac address
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *
+wlan_get_station_entry(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+
+ if (!mac) {
+ LEAVE();
+ return MNULL;
+ }
+ if (!(sta_ptr = (sta_node *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+ while (sta_ptr != (sta_node *) & priv->sta_list) {
+ if (!memcmp
+ (priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return sta_ptr;
+ }
+ sta_ptr = sta_ptr->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will add a pointer to station entry in station list
+ * table with the give mac address, if it does not exist already
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *
+wlan_add_station_entry(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ sta_ptr = wlan_get_station_entry(priv, mac);
+ if (sta_ptr)
+ goto done;
+ if (priv->adapter->callbacks.
+ moal_malloc(priv->adapter->pmoal_handle, sizeof(sta_node), MLAN_MEM_DEF,
+ (t_u8 **) & sta_ptr)) {
+ PRINTM(MERROR, "Failed to allocate memory for station node\n");
+ LEAVE();
+ return MNULL;
+ }
+ memset(priv->adapter, sta_ptr, 0, sizeof(sta_node));
+ memcpy(priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH);
+ util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->sta_list,
+ (pmlan_linked_list) sta_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ done:
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return sta_ptr;
+}
+
+/**
+ * @brief This function will delete a station entry from station list
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station's mac address
+ *
+ * @return N/A
+ */
+t_void
+wlan_delete_station_entry(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if ((sta_ptr = wlan_get_station_entry(priv, mac))) {
+ util_unlink_list(priv->adapter->pmoal_handle, &priv->sta_list,
+ (pmlan_linked_list) sta_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
+ (t_u8 *) sta_ptr);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Clean up wapi station list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_delete_station_list(pmlan_private priv)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+ while ((sta_ptr =
+ (sta_node *) util_dequeue_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
+ (t_u8 *) sta_ptr);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get extended version information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_get_info_ver_ext(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_get_info *pinfo = (mlan_ds_get_info *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET,
+ 0,
+ (t_void *) pioctl_req,
+ &pinfo->param.ver_ext.version_str_sel);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set driver debug bit masks in order to enhance performance
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_set_drvdbg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Set driver debug bit masks */
+ drvdbg = misc->param.drvdbg;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Rx mgmt frame forward register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_reg_rx_mgmt_ind(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Set passthru mask for mgmt frame */
+ pmpriv->mgmt_frame_passthru_mask = misc->param.mgmt_subtype_mask;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_RX_MGMT_IND,
+ pioctl_req->action,
+ 0,
+ (t_void *) pioctl_req,
+ &misc->param.mgmt_subtype_mask);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes the 802.11 mgmt Frame
+ *
+ * @param priv A pointer to mlan_private
+ * @param payload A pointer to the received buffer
+ * @param payload_len Length of the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_802dot11_mgmt_pkt(IN mlan_private * priv,
+ IN t_u8 * payload, IN t_u32 payload_len)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_802_11_header *pieee_pkt_hdr = MNULL;
+ t_u16 sub_type = 0;
+ t_u8 *event_buf = MNULL;
+ mlan_event *pevent = MNULL;
+ t_u8 unicast = 0;
+
+ ENTER();
+ if (payload_len > (MAX_EVENT_SIZE - sizeof(mlan_event))) {
+ PRINTM(MERROR, "Dropping large mgmt frame,len =%d\n", payload_len);
+ LEAVE();
+ return ret;
+ }
+ /* Check packet type-subtype and compare with mgmt_passthru_mask If event
+ is needed to host, just eventify it */
+ pieee_pkt_hdr = (wlan_802_11_header *) payload;
+ sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(pieee_pkt_hdr->frm_ctl);
+ if (((1 << sub_type) & priv->mgmt_frame_passthru_mask) == 0) {
+ PRINTM(MINFO, "Dropping mgmt frame for subtype %d.\n", sub_type);
+ LEAVE();
+ return ret;
+ }
+ switch (sub_type) {
+ case SUBTYPE_ASSOC_REQUEST:
+ case SUBTYPE_REASSOC_REQUEST:
+ case SUBTYPE_DISASSOC:
+ case SUBTYPE_DEAUTH:
+ case SUBTYPE_ACTION:
+ case SUBTYPE_AUTH:
+ case SUBTYPE_PROBE_RESP:
+ unicast = MTRUE;
+ break;
+ default:
+ break;
+ }
+ if (unicast == MTRUE) {
+ if (memcmp
+ (pmadapter, pieee_pkt_hdr->addr1, priv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MINFO,
+ "Dropping mgmt frame for others: type=%d %02x:%02x:%02x:%02x:%02x:%02x\n",
+ sub_type, pieee_pkt_hdr->addr1[0], pieee_pkt_hdr->addr1[1],
+ pieee_pkt_hdr->addr1[2], pieee_pkt_hdr->addr1[3],
+ pieee_pkt_hdr->addr1[4], pieee_pkt_hdr->addr1[5]);
+ LEAVE();
+ return ret;
+ }
+ }
+ /* Allocate memory for event buffer */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF,
+ &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pevent = (pmlan_event) event_buf;
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_MGMT_FRAME;
+ pevent->event_len = payload_len + sizeof(pevent->event_id);
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) & pevent->event_id, sizeof(pevent->event_id));
+ memcpy(pmadapter, (t_u8 *) (pevent->event_buf + sizeof(pevent->event_id)),
+ payload, payload_len);
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_MGMT_FRAME, pevent);
+
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get OTP user data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_otp_user_data(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ if (misc->param.otp_user_data.user_data_length > MAX_OTP_USER_DATA_LEN) {
+ PRINTM(MERROR, "Invalid OTP user data length\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return ret;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_OTP_READ_USER_DATA,
+ HostCmd_ACT_GEN_GET,
+ 0,
+ (t_void *) pioctl_req, &misc->param.otp_user_data);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param ie_buf A pointer to ie_buf
+ * @param ie_len total ie length
+ * @param id ie's id
+ *
+ * @return ie's poiner or MNULL
+ */
+t_u8 *
+wlan_get_specific_ie(pmlan_private priv, t_u8 * ie_buf, t_u8 ie_len,
+ IEEEtypes_ElementId_e id)
+{
+ t_u32 bytes_left = ie_len;
+ t_u8 *pcurrent_ptr = ie_buf;
+ t_u16 total_ie_len;
+ t_u8 *ie_ptr = MNULL;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "ie", ie_buf, ie_len);
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+ if (element_id == id) {
+ PRINTM(MCMND, "Find IE: id=%d\n", id);
+ DBG_HEXDUMP(MCMND, "IE", pcurrent_ptr, total_ie_len);
+ ie_ptr = pcurrent_ptr;
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+
+ LEAVE();
+
+ return ie_ptr;
+}
+
+/**
+ * @brief Get pm info
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status
+wlan_get_pm_info(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ pm_cfg->param.ps_info.is_suspend_allowed = MTRUE;
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)
+ || pmadapter->curr_cmd || !wlan_bypass_tx_list_empty(pmadapter)
+ || !wlan_wmm_lists_empty(pmadapter)
+ || pmadapter->sdio_ireg) {
+ pm_cfg->param.ps_info.is_suspend_allowed = MFALSE;
+ PRINTM(MIOCTL,
+ "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d sdio_ireg=0x%x\n",
+ util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock), pmadapter->curr_cmd,
+ wlan_wmm_lists_empty(pmadapter),
+ wlan_bypass_tx_list_empty(pmadapter), pmadapter->sdio_ireg);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_radio_ioctl_radio_ctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmadapter->radio_on == radio_cfg->param.radio_on_off) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RADIO_CONTROL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ &radio_cfg->param.radio_on_off);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get antenna 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
+ */
+mlan_status
+wlan_radio_ioctl_ant_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_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_ds_ant_cfg *ant_cfg;
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ ant_cfg = &radio_cfg->param.ant_cfg;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* User input validation */
+ if (!ant_cfg->tx_antenna ||
+ ant_cfg->tx_antenna & ~RF_ANTENNA_MASK(pmadapter->
+ number_of_antenna)) {
+ PRINTM(MERROR, "Invalid antenna setting\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (ant_cfg->rx_antenna) {
+ if (ant_cfg->
+ rx_antenna & ~RF_ANTENNA_MASK(pmadapter->number_of_antenna)) {
+ PRINTM(MERROR, "Invalid antenna setting\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ } else
+ ant_cfg->rx_antenna = ant_cfg->tx_antenna;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_ANTENNA,
+ cmd_action,
+ 0, (t_void *) pioctl_req, (t_void *) ant_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_rate_value(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ rate->param.rate_cfg.is_rate_auto = pmpriv->is_data_rate_auto;
+ pioctl_req->data_read_written =
+ sizeof(mlan_rate_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+
+ /* If not connected, set rate to the lowest in each band */
+ if (pmpriv->media_connected != MTRUE) {
+ if (pmpriv->config_bands & (BAND_B | BAND_G)) {
+ /* Return the lowest supported rate for BG band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ } else if (pmpriv->config_bands & (BAND_A | BAND_B)) {
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_A) {
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_G) {
+ /* Return the lowest supported rate for G band */
+ rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_B) {
+ /* Return the lowest supported rate for B band */
+ rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_GN) {
+ /* Return the lowest supported rate for N band */
+ rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
+ } else {
+ PRINTM(MMSG, "Invalid Band 0x%x\n", pmpriv->config_bands);
+ }
+
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate value
+ *
+ * @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_rate_ioctl_set_rate_value(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *ds_rate = MNULL;
+ WLAN_802_11_RATES rates;
+ t_u8 *rate = MNULL;
+ int rate_index = 0;
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ t_u32 i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3; i++)
+ bitmap_rates[i + 2] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ memset(pmadapter, rates, 0, sizeof(rates));
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
+ pmpriv->config_bands : pmadapter->
+ adhoc_start_band, rates);
+ rate = rates;
+ for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) {
+ PRINTM(MINFO, "Rate=0x%X Wanted=0x%X\n", rate[i],
+ ds_rate->param.rate_cfg.rate);
+ if ((rate[i] & 0x7f) == (ds_rate->param.rate_cfg.rate & 0x7f))
+ break;
+ }
+ if (!rate[i] || (i == WLAN_SUPPORTED_RATES)) {
+ PRINTM(MERROR, "The fixed data rate 0x%X is out "
+ "of range\n", ds_rate->param.rate_cfg.rate);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+
+ rate_index =
+ wlan_data_rate_to_index(pmadapter, ds_rate->param.rate_cfg.rate);
+
+ /* Only allow b/g rates to be set */
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3)
+ bitmap_rates[0] = 1 << rate_index;
+ else {
+ rate_index -= 1; /* There is a 0x00 in the table */
+ if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7)
+ bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
+ }
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate index
+ *
+ * @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_rate_ioctl_get_rate_index(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];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate index
+ *
+ * @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_rate_ioctl_set_rate_index(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ t_u32 rate_index;
+ t_u32 i;
+ mlan_ds_rate *ds_rate = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ int tx_mcs_supp = GET_TXMCSSUPP(pmadapter->usr_dev_mcs_support);
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ rate_index = ds_rate->param.rate_cfg.rate;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Rates talbe [0]: HR/DSSS;[1]: OFDM; [2..9] HT; */
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 2; i < 9; i++)
+ bitmap_rates[i] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ PRINTM(MINFO, "Rate index is %d\n", rate_index);
+ if ((rate_index > MLAN_RATE_INDEX_MCS7 &&
+ rate_index <= MLAN_RATE_INDEX_MCS15) && (tx_mcs_supp < 2)) {
+ PRINTM(MERROR,
+ "HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n",
+ rate_index, pmadapter->usr_dev_mcs_support);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Bitmap of HR/DSSS rates */
+ if ((rate_index >= MLAN_RATE_INDEX_HRDSSS0) &&
+ (rate_index <= MLAN_RATE_INDEX_HRDSSS3)) {
+ bitmap_rates[0] = 1 << rate_index;
+ ret = MLAN_STATUS_SUCCESS;
+ /* Bitmap of OFDM rates */
+ } else if ((rate_index >= MLAN_RATE_INDEX_OFDM0) &&
+ (rate_index <= MLAN_RATE_INDEX_OFDM7)) {
+ bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ if ((rate_index >= MLAN_RATE_INDEX_MCS0) &&
+ (rate_index <= MLAN_RATE_INDEX_MCS32)) {
+ rate_index -= MLAN_RATE_INDEX_MCS0;
+ bitmap_rates[2 + (rate_index / 16)] = 1 << (rate_index % 16);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "Invalid MCS index=%d. \n", rate_index);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ PRINTM(MINFO, "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
+ "IsRateAuto=%d, DataRate=%d\n",
+ bitmap_rates[9], bitmap_rates[8],
+ bitmap_rates[7], bitmap_rates[6],
+ bitmap_rates[5], bitmap_rates[4],
+ bitmap_rates[3], bitmap_rates[2],
+ bitmap_rates[1], bitmap_rates[0],
+ pmpriv->is_data_rate_auto, pmpriv->data_rate);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, (t_void *) bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_rate_ioctl_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_value(pmadapter, pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_value(pmadapter, pioctl_req);
+ } else {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_index(pmadapter, pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_index(pmadapter, pioctl_req);
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function prepares command of rf_antenna.
+ *
+ * @param pmpriv 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_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &cmd->params.antenna;
+ mlan_ds_ant_cfg *ant_cfg = (mlan_ds_ant_cfg *) pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_SET_TX);
+ pantenna->tx_antenna_mode =
+ wlan_cpu_to_le16((t_u16) ant_cfg->tx_antenna);
+ pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_SET_RX);
+ pantenna->rx_antenna_mode =
+ wlan_cpu_to_le16((t_u16) ant_cfg->rx_antenna);
+ } else {
+ pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_GET_TX);
+ pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_GET_RX);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_antenna
+ *
+ * @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_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &resp->params.antenna;
+ t_u16 tx_ant_mode = wlan_le16_to_cpu(pantenna->tx_antenna_mode);
+ t_u16 rx_ant_mode = wlan_le16_to_cpu(pantenna->rx_antenna_mode);
+ mlan_ds_radio_cfg *radio = MNULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x"
+ " Rx action = 0x%x, Rx Mode = 0x%04x\n",
+ wlan_le16_to_cpu(pantenna->action_tx), tx_ant_mode,
+ wlan_le16_to_cpu(pantenna->action_rx), rx_ant_mode);
+
+ if (pioctl_buf) {
+ radio = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio->param.ant_cfg.tx_antenna = tx_ant_mode;
+ radio->param.ant_cfg.rx_antenna = rx_ant_mode;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief Set/Get wifi_direct_mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_bss_ioctl_wifi_direct_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) 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,
+ HOST_CMD_WIFI_DIRECT_MODE_CONFIG,
+ cmd_action,
+ 0, (t_void *) pioctl_req, &bss->param.wfd_mode);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get remain on channel setting
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_radio_ioctl_remain_chan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_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_802_11_REMAIN_ON_CHANNEL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ &radio_cfg->param.remain_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_module.c b/drivers/net/wireless/sd8797/mlan/mlan_module.c
new file mode 100644
index 000000000000..cd0bd0c5fb78
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_module.c
@@ -0,0 +1,47 @@
+/** @file mlan_module.c
+ *
+ * @brief This file declares the exported symbols from MLAN.
+ *
+ * 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:
+ 12/08/2008: initial version
+******************************************************/
+
+#ifdef LINUX
+#include <linux/module.h>
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+
+EXPORT_SYMBOL(mlan_register);
+EXPORT_SYMBOL(mlan_unregister);
+EXPORT_SYMBOL(mlan_init_fw);
+EXPORT_SYMBOL(mlan_set_init_param);
+EXPORT_SYMBOL(mlan_dnld_fw);
+EXPORT_SYMBOL(mlan_shutdown_fw);
+EXPORT_SYMBOL(mlan_send_packet);
+EXPORT_SYMBOL(mlan_ioctl);
+EXPORT_SYMBOL(mlan_main_process);
+EXPORT_SYMBOL(mlan_select_wmm_queue);
+EXPORT_SYMBOL(mlan_interrupt);
+
+MODULE_DESCRIPTION("M-WLAN MLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
+#endif /* LINUX */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_scan.c b/drivers/net/wireless/sd8797/mlan/mlan_scan.c
new file mode 100644
index 000000000000..895fb38a5786
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_scan.c
@@ -0,0 +1,4223 @@
+/** @file mlan_scan.c
+ *
+ * @brief Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending scan commands to the firmware.
+ *
+ * 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/28/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Constants
+********************************************************/
+
+/** The maximum number of channels the firmware can scan per command */
+#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
+
+/**
+ * Number of channels to scan per firmware scan command issuance.
+ *
+ * Number restricted to prevent hitting the limit on the amount of scan data
+ * returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
+
+/** Memory needed to store a max sized Channel List TLV for a firmware scan */
+#define CHAN_TLV_MAX_SIZE (sizeof(MrvlIEtypesHeader_t) \
+ + (MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN \
+ * sizeof(ChanScanParamSet_t)))
+
+/** Memory needed to store supported rate */
+#define RATE_TLV_MAX_SIZE (sizeof(MrvlIEtypes_RatesParamSet_t) + HOSTCMD_SUPPORTED_RATES)
+
+/** Memory needed to store a max number/size WildCard SSID TLV for a firmware scan */
+#define WILDCARD_SSID_TLV_MAX_SIZE \
+ (MRVDRV_MAX_SSID_LIST_LENGTH * (sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + MRVDRV_MAX_SSID_LENGTH))
+
+/** WPS TLV MAX size is MAX IE size plus 2 bytes for t_u16 MRVL TLV extension */
+#define WPS_TLV_MAX_SIZE (sizeof(IEEEtypes_VendorSpecific_t) + 2)
+/** Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max */
+#define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config) \
+ + sizeof(MrvlIEtypes_NumProbes_t) \
+ + sizeof(MrvlIETypes_HTCap_t) \
+ + CHAN_TLV_MAX_SIZE \
+ + RATE_TLV_MAX_SIZE \
+ + WILDCARD_SSID_TLV_MAX_SIZE \
+ + WPS_TLV_MAX_SIZE)
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/**
+ * Interally used to send a configured scan cmd between driver routines
+ */
+typedef union
+{
+ /** Scan configuration (variable length) */
+ wlan_scan_cmd_config config;
+ /** Max allocated block */
+ t_u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
+} wlan_scan_cmd_config_tlv;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/** Cipher suite definition */
+enum cipher_suite
+{
+ CIPHER_SUITE_TKIP,
+ CIPHER_SUITE_CCMP,
+ CIPHER_SUITE_MAX
+};
+
+static t_u8 wpa_oui[CIPHER_SUITE_MAX][4] = {
+ {0x00, 0x50, 0xf2, 0x02}, /* TKIP */
+ {0x00, 0x50, 0xf2, 0x04}, /* AES */
+};
+
+static t_u8 rsn_oui[CIPHER_SUITE_MAX][4] = {
+ {0x00, 0x0f, 0xac, 0x02}, /* TKIP */
+ {0x00, 0x0f, 0xac, 0x04}, /* AES */
+};
+
+/**
+ * @brief This function will parse a given IE for a given OUI
+ *
+ * Parse a given WPA/RSN IE to find if it has a given oui in PTK,
+ * if no OUI found for PTK it returns 0.
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find OUI, 1 on success.
+ */
+static t_u8
+search_oui_in_ie(mlan_adapter * pmadapter, IEBody * ie_body, t_u8 * oui)
+{
+ t_u8 count;
+
+ count = ie_body->PtkCnt[0];
+
+ ENTER();
+ /* There could be multiple OUIs for PTK hence 1) Take the length. 2) Check
+ all the OUIs for AES. 3) If one of them is AES then pass success. */
+ while (count) {
+ if (!memcmp(pmadapter, ie_body->PtkBody, oui, sizeof(ie_body->PtkBody))) {
+ LEAVE();
+ return MLAN_OUI_PRESENT;
+ }
+
+ --count;
+ if (count) {
+ ie_body = (IEBody *) ((t_u8 *) ie_body + sizeof(ie_body->PtkBody));
+ }
+ }
+
+ PRINTM(MINFO, "The OUI %x:%x:%x:%x is not found in PTK \n", oui[0], oui[1],
+ oui[2], oui[3]);
+ LEAVE();
+ return MLAN_OUI_NOT_PRESENT;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if RSN IE has AES
+ * OUI in it. If RSN IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8
+is_rsn_oui_present(mlan_adapter * pmadapter, BSSDescriptor_t * pbss_desc,
+ t_u32 cipher_suite)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ if (((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
+ ie_body =
+ (IEBody *) (((t_u8 *) pbss_desc->prsn_ie->data) +
+ RSN_GTK_OUI_OFFSET);
+ oui = &rsn_oui[cipher_suite][0];
+ if ((ret = search_oui_in_ie(pmadapter, ie_body, oui))) {
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if WPA IE has AES
+ * OUI in it. If WPA IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8
+is_wpa_oui_present(mlan_adapter * pmadapter, BSSDescriptor_t * pbss_desc,
+ t_u32 cipher_suite)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))) {
+ ie_body = (IEBody *) pbss_desc->pwpa_ie->data;
+ oui = &wpa_oui[cipher_suite][0];
+ if ((ret = search_oui_in_ie(pmadapter, ie_body, oui))) {
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief compare config band and a band from the scan result,
+ * which is defined by functiion radio_type_to_band(t_u8 radio_type) above
+ *
+ * @param cfg_band: band configured
+ * scan_band: band from scan result
+ *
+ * @return matched: non-zero. unmatched: 0
+ *
+ */
+static t_u8
+wlan_is_band_compatible(t_u8 cfg_band, t_u8 scan_band)
+{
+ t_u8 band;
+ switch (scan_band) {
+ case BAND_A:
+ band = BAND_A | BAND_AN;
+ break;
+ case BAND_G:
+ default:
+ band = BAND_B | BAND_G | BAND_GN;
+ }
+ return cfg_band & band;
+}
+
+/**
+ * @brief This function finds the best SSID in the Scan List
+ *
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @return index in BSSID list
+ */
+static t_s32
+wlan_find_best_network_in_list(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 mode = pmpriv->bss_mode;
+ t_s32 best_net = -1;
+ t_s32 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Num of BSSIDs = %d\n", pmadapter->num_in_scan_table);
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++) {
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ if (wlan_is_network_compatible(pmpriv, i, mode) >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ break;
+ }
+ }
+
+ LEAVE();
+ return best_net;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan configuration parameters
+ * @param pscan_chan_list Output parameter: Resulting channel list to scan
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID filter
+ * is being sent in the command to firmware. Used to
+ * increase the number of channels sent in a scan
+ * command and to disable the firmware channel scan
+ * filter.
+ *
+ * @return N/A
+ */
+static t_void
+wlan_scan_create_channel_list(IN mlan_private * pmpriv,
+ IN const wlan_user_scan_cfg * puser_scan_in,
+ OUT ChanScanParamSet_t * pscan_chan_list,
+ IN t_u8 filtered_scan)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx = 0;
+ t_u32 next_chan;
+ t_u8 scan_type;
+ t_u8 radio_type;
+
+ ENTER();
+
+ for (region_idx = 0;
+ region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
+
+ if (wlan_11d_is_enabled(pmpriv) && pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ if (puser_scan_in && !puser_scan_in->chan_list[0].chan_number &&
+ puser_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
+ radio_type =
+ puser_scan_in->chan_list[0].radio_type & ~BAND_SPECIFIED;
+ if (!radio_type && (pscan_region->band != BAND_B) &&
+ (pscan_region->band != BAND_G))
+ continue;
+ if (radio_type && (pscan_region->band != BAND_A))
+ continue;
+ }
+ if (!wlan_is_band_compatible
+ (pmpriv->config_bands | pmadapter->adhoc_start_band,
+ pscan_region->band))
+ continue;
+ for (next_chan = 0;
+ next_chan < pscan_region->num_cfp; next_chan++, chan_idx++) {
+ /* Set the default scan type to the user specified type, will later
+ be changed to passive on a per channel basis if restricted by
+ regulatory requirements (11d or 11h) */
+ scan_type = pmadapter->scan_type;
+ cfp = pscan_region->pcfp + next_chan;
+
+ if (scan_type == MLAN_SCAN_TYPE_ACTIVE
+ && wlan_11d_is_enabled(pmpriv)) {
+ scan_type = wlan_11d_get_scan_type(pmadapter,
+ pscan_region->band,
+ (t_u8) cfp->channel,
+ &pmadapter->
+ parsed_region_chan);
+ }
+
+ switch (pscan_region->band) {
+ case BAND_A:
+ pscan_chan_list[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_A;
+ if (!wlan_11d_is_enabled(pmpriv)) {
+ /* 11D not available... play it safe on DFS channels */
+ if (wlan_11h_radar_detect_required
+ (pmpriv, (t_u8) cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ if (wlan_bg_scan_type_is_passive(pmpriv, (t_u8) cfp->channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ default:
+ pscan_chan_list[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].scan_time) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16((t_u16) puser_scan_in->chan_list[0].
+ scan_time);
+ } else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ } else if (filtered_scan) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ } else {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->active_scan_time);
+ }
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ pscan_chan_list[chan_idx].chan_scan_mode.passive_scan = MTRUE;
+ } else {
+ pscan_chan_list[chan_idx].chan_scan_mode.passive_scan = MFALSE;
+ }
+
+ pscan_chan_list[chan_idx].chan_number = (t_u8) cfp->channel;
+
+ if (filtered_scan) {
+ pscan_chan_list[chan_idx].chan_scan_mode.disable_chan_filt =
+ MTRUE;
+ }
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Add WPS IE to probe request frame
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pptlv_out A pointer to TLV to fill in
+ *
+ * @return N/A
+ */
+static void
+wlan_add_wps_probe_request_ie(IN mlan_private * pmpriv, OUT t_u8 ** pptlv_out)
+{
+ MrvlIEtypesHeader_t *tlv;
+
+ ENTER();
+
+ if (pmpriv->wps.wps_ie.vend_hdr.len) {
+ tlv = (MrvlIEtypesHeader_t *) * pptlv_out;
+ tlv->type = wlan_cpu_to_le16(VENDOR_SPECIFIC_221);
+ tlv->len = wlan_cpu_to_le16(pmpriv->wps.wps_ie.vend_hdr.len);
+ *pptlv_out += sizeof(MrvlIEtypesHeader_t);
+ memcpy(pmpriv->adapter, *pptlv_out,
+ pmpriv->wps.wps_ie.vend_hdr.oui,
+ pmpriv->wps.wps_ie.vend_hdr.len);
+ *pptlv_out += (pmpriv->wps.wps_ie.vend_hdr.len
+ + sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Construct and send multiple scan config commands to the firmware
+ *
+ * Previous routines have created a wlan_scan_cmd_config with any requested
+ * TLVs. This function splits the channel TLV into max_chan_per_scan lists
+ * and sends the portion of the channel TLV along with the other TLVs
+ * to the wlan_cmd routines for execution in the firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param max_chan_per_scan Maximum number channels to be included in each
+ * scan command sent to firmware
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID
+ * filter is being used for the firmware command
+ * scan command sent to firmware
+ * @param pscan_cfg_out Scan configuration used for this scan.
+ * @param pchan_tlv_out Pointer in the pscan_cfg_out where the channel TLV
+ * should start. This is past any other TLVs that
+ * must be sent down in each firmware command.
+ * @param pscan_chan_list List of channels to scan in max_chan_per_scan segments
+ *
+ * @return MLAN_STATUS_SUCCESS or error return otherwise
+ */
+static mlan_status
+wlan_scan_channel_list(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN t_u32 max_chan_per_scan,
+ IN t_u8 filtered_scan,
+ OUT wlan_scan_cmd_config * pscan_cfg_out,
+ OUT MrvlIEtypes_ChanListParamSet_t * pchan_tlv_out,
+ IN ChanScanParamSet_t * pscan_chan_list)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ChanScanParamSet_t *ptmp_chan_list;
+ ChanScanParamSet_t *pstart_chan;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ t_u32 tlv_idx;
+ t_u32 total_scan_time;
+ t_u32 done_early;
+ t_u32 cmd_no;
+
+ ENTER();
+
+ if (!pscan_cfg_out || !pchan_tlv_out || !pscan_chan_list) {
+ PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n",
+ pscan_cfg_out, pchan_tlv_out, pscan_chan_list);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!pscan_chan_list->chan_number) {
+ PRINTM(MERROR, "Scan: No channel configured\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired list */
+ ptmp_chan_list = pscan_chan_list;
+
+ /* Loop through the desired channel list, sending a new firmware scan
+ commands for each max_chan_per_scan channels (or for 1,6,11 individually
+ if configured accordingly) */
+ while (ptmp_chan_list->chan_number) {
+
+ tlv_idx = 0;
+ total_scan_time = 0;
+ pchan_tlv_out->header.len = 0;
+ pstart_chan = ptmp_chan_list;
+ done_early = MFALSE;
+
+ /*
+ * Construct the Channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlv_idx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired channel list)
+ * - done_early is set (controlling individual scanning of 1,6,11)
+ */
+ while (tlv_idx < max_chan_per_scan && ptmp_chan_list->chan_number &&
+ !done_early) {
+
+ PRINTM(MINFO, "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n",
+ ptmp_chan_list->chan_number,
+ ptmp_chan_list->radio_type,
+ ptmp_chan_list->chan_scan_mode.passive_scan,
+ ptmp_chan_list->chan_scan_mode.disable_chan_filt,
+ wlan_le16_to_cpu(ptmp_chan_list->max_scan_time));
+
+ /* Copy the current channel TLV to the command being prepared */
+ memcpy(pmadapter, pchan_tlv_out->chan_scan_param + tlv_idx,
+ ptmp_chan_list, sizeof(pchan_tlv_out->chan_scan_param));
+
+ /* Increment the TLV header length by the size appended */
+ pchan_tlv_out->header.len += sizeof(pchan_tlv_out->chan_scan_param);
+
+ /*
+ * The tlv buffer length is set to the number of bytes of the
+ * between the channel tlv pointer and the start of the
+ * tlv buffer. This compensates for any TLVs that were appended
+ * before the channel list.
+ */
+ pscan_cfg_out->tlv_buf_len = (t_u32) ((t_u8 *) pchan_tlv_out
+ - pscan_cfg_out->tlv_buf);
+
+ /* Add the size of the channel tlv header and the data length */
+ pscan_cfg_out->tlv_buf_len += (sizeof(pchan_tlv_out->header)
+ + pchan_tlv_out->header.len);
+
+ /* Increment the index to the channel tlv we are constructing */
+ tlv_idx++;
+
+ /* Count the total scan time per command */
+ total_scan_time += wlan_le16_to_cpu(ptmp_chan_list->max_scan_time);
+
+ done_early = MFALSE;
+
+ /* Stop the loop if the *current* channel is in the 1,6,11 set and
+ we are not filtering on a BSSID or SSID. */
+ if (!filtered_scan && (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+
+ /* Increment the tmp pointer to the next channel to be scanned */
+ ptmp_chan_list++;
+
+ /* Stop the loop if the *next* channel is in the 1,6,11 set. This
+ will cause it to be the only channel scanned on the next
+ interation */
+ if (!filtered_scan && (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+ }
+
+ /* The total scan time should be less than scan command timeout value */
+ if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME) {
+ PRINTM(MMSG,
+ "Total scan time %d ms is over limit (%d ms), scan skipped\n",
+ total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pchan_tlv_out->header.len = wlan_cpu_to_le16(pchan_tlv_out->header.len);
+
+ pmadapter->pscan_channels = pstart_chan;
+
+ /* Send the scan command to the firmware with the specified cfg */
+ if (pmadapter->ext_scan)
+ cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
+ else
+ cmd_no = HostCmd_CMD_802_11_SCAN;
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd_no,
+ HostCmd_ACT_GEN_SET,
+ 0, pioctl_buf, pscan_cfg_out);
+ if (ret)
+ break;
+ }
+
+ LEAVE();
+
+ if (ret) {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Construct a wlan_scan_cmd_config structure to use in scan commands
+ *
+ * Application layer or other functions can invoke wlan_scan_networks
+ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ * This structure is used as the basis of one or many wlan_scan_cmd_config
+ * commands that are sent to the command processing module and sent to
+ * firmware.
+ *
+ * Create a wlan_scan_cmd_config based on the following user supplied
+ * parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - Channel list
+ *
+ * If the SSID or BSSID filter is not present, disable/clear the filter.
+ * If the number of probes is not set, use the adapter default setting
+ * Qualify the channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan config parameters
+ * @param pscan_cfg_out Output parameter: Resulting scan configuration
+ * @param ppchan_list_out Output parameter: Pointer to the start of the
+ * channel TLV portion of the output scan config
+ * @param pscan_chan_list Output parameter: Pointer to the resulting
+ * channel list to scan
+ * @param pmax_chan_per_scan Output parameter: Number of channels to scan for
+ * each issuance of the firmware scan command
+ * @param pfiltered_scan Output parameter: Flag indicating whether or not
+ * a BSSID or SSID filter is being sent in the
+ * command to firmware. Used to increase the number
+ * of channels sent in a scan command and to
+ * disable the firmware channel scan filter.
+ * @param pscan_current_only Output parameter: Flag indicating whether or not
+ * we are only scanning our current active channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_scan_setup_scan_config(IN mlan_private * pmpriv,
+ IN const wlan_user_scan_cfg * puser_scan_in,
+ OUT wlan_scan_cmd_config * pscan_cfg_out,
+ OUT MrvlIEtypes_ChanListParamSet_t **
+ ppchan_list_out,
+ OUT ChanScanParamSet_t * pscan_chan_list,
+ OUT t_u8 * pmax_chan_per_scan,
+ OUT t_u8 * pfiltered_scan,
+ OUT t_u8 * pscan_current_only)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *ptlv_pos;
+ t_u32 num_probes;
+ t_u32 ssid_len;
+ t_u32 chan_idx;
+ t_u32 scan_type;
+ t_u16 scan_dur;
+ t_u8 channel;
+ t_u8 radio_type;
+ t_u32 ssid_idx;
+ t_u8 ssid_filter;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ MrvlIETypes_HTCap_t *pht_cap;
+
+ ENTER();
+
+ /* The tlv_buf_len is calculated for each scan command. The TLVs added in
+ this routine will be preserved since the routine that sends the command
+ will append channelTLVs at *ppchan_list_out. The difference between the
+ *ppchan_list_out and the tlv_buf start will be used to calculate the
+ size of anything we add in this routine. */
+ pscan_cfg_out->tlv_buf_len = 0;
+
+ /* Running tlv pointer. Assigned to ppchan_list_out at end of function so
+ later routines know where channels can be added to the command buf */
+ ptlv_pos = pscan_cfg_out->tlv_buf;
+
+ /* Initialize the scan as un-filtered; the flag is later set to TRUE below
+ if a SSID or BSSID filter is sent in the command */
+ *pfiltered_scan = MFALSE;
+
+ /* Initialize the scan as not being only on the current channel. If the
+ channel list is customized, only contains one channel, and is the active
+ channel, this is set true and data flow is not halted. */
+ *pscan_current_only = MFALSE;
+
+ if (puser_scan_in) {
+
+ ssid_filter = MFALSE;
+
+ /* Set the bss type scan filter, use Adapter setting if unset */
+ pscan_cfg_out->bss_mode = (puser_scan_in->bss_mode
+ ? (t_u8) puser_scan_in->bss_mode :
+ (t_u8) pmadapter->scan_mode);
+
+ /* Set the number of probes to send, use Adapter setting if unset */
+ num_probes = (puser_scan_in->num_probes ? puser_scan_in->num_probes :
+ pmadapter->scan_probes);
+
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled (all zeros).
+ */
+ memcpy(pmadapter, pscan_cfg_out->specific_bssid,
+ puser_scan_in->specific_bssid,
+ sizeof(pscan_cfg_out->specific_bssid));
+
+ for (ssid_idx = 0; ((ssid_idx < NELEMENTS(puser_scan_in->ssid_list))
+ && (*puser_scan_in->ssid_list[ssid_idx].ssid ||
+ puser_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+
+ ssid_len =
+ wlan_strlen((t_s8 *) puser_scan_in->ssid_list[ssid_idx].ssid);
+
+ pwildcard_ssid_tlv
+ = (MrvlIEtypes_WildCardSsIdParamSet_t *) ptlv_pos;
+ pwildcard_ssid_tlv->header.type
+ = wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len
+ = (t_u16) (ssid_len
+ + sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length
+ = puser_scan_in->ssid_list[ssid_idx].max_len;
+
+ memcpy(pmadapter, pwildcard_ssid_tlv->ssid,
+ puser_scan_in->ssid_list[ssid_idx].ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, ssid_len));
+
+ ptlv_pos += (sizeof(pwildcard_ssid_tlv->header)
+ + pwildcard_ssid_tlv->header.len);
+
+ pwildcard_ssid_tlv->header.len
+ = wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
+
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n",
+ ssid_idx,
+ pwildcard_ssid_tlv->ssid,
+ pwildcard_ssid_tlv->max_ssid_length);
+
+ if (ssid_len) {
+ ssid_filter = MTRUE;
+ }
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not truncate
+ * scan results. That is not an issue with an SSID or BSSID
+ * filter applied to the scan results in the firmware.
+ */
+ if ((ssid_idx && ssid_filter) ||
+ memcmp(pmadapter, pscan_cfg_out->specific_bssid, &zero_mac,
+ sizeof(zero_mac))) {
+ *pfiltered_scan = MTRUE;
+ }
+
+ } else {
+ pscan_cfg_out->bss_mode = (t_u8) pmadapter->scan_mode;
+ num_probes = pmadapter->scan_probes;
+ }
+
+ /*
+ * If a specific BSSID or SSID is used, the number of channels in the
+ * scan command will be increased to the absolute maximum.
+ */
+ if (*pfiltered_scan)
+ *pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ else
+ *pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+ /* If the input config or adapter has the number of Probes set, add tlv */
+ if (num_probes) {
+
+ PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
+
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *) ptlv_pos;
+ pnum_probes_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len = sizeof(pnum_probes_tlv->num_probes);
+ pnum_probes_tlv->num_probes = wlan_cpu_to_le16((t_u16) num_probes);
+
+ ptlv_pos +=
+ sizeof(pnum_probes_tlv->header) + pnum_probes_tlv->header.len;
+
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(pnum_probes_tlv->header.len);
+ }
+
+ /* Append rates tlv */
+ memset(pmadapter, rates, 0, sizeof(rates));
+
+ rates_size = wlan_get_supported_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode ==
+ MLAN_BSS_MODE_INFRA) ? pmpriv->
+ config_bands : pmadapter->
+ adhoc_start_band, rates);
+
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *) ptlv_pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16) rates_size);
+ memcpy(pmadapter, prates_tlv->rates, rates, rates_size);
+ ptlv_pos += sizeof(prates_tlv->header) + rates_size;
+
+ PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
+
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
+ && (pmpriv->config_bands & BAND_GN || pmpriv->config_bands & BAND_AN)) {
+ pht_cap = (MrvlIETypes_HTCap_t *) ptlv_pos;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands);
+ HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ wlan_add_wps_probe_request_ie(pmpriv, &ptlv_pos);
+
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this function (SSID, num_probes).
+ * Channel TLVs will be added past this for each scan command, preserving
+ * the TLVs that were previously added.
+ */
+ *ppchan_list_out = (MrvlIEtypes_ChanListParamSet_t *) ptlv_pos;
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].chan_number) {
+
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+
+ for (chan_idx = 0;
+ chan_idx < WLAN_USER_SCAN_CHAN_MAX
+ && puser_scan_in->chan_list[chan_idx].chan_number; chan_idx++) {
+
+ channel = puser_scan_in->chan_list[chan_idx].chan_number;
+ (pscan_chan_list + chan_idx)->chan_number = channel;
+
+ radio_type = puser_scan_in->chan_list[chan_idx].radio_type;
+ (pscan_chan_list + chan_idx)->radio_type = radio_type;
+
+ scan_type = puser_scan_in->chan_list[chan_idx].scan_type;
+ if (scan_type == MLAN_SCAN_TYPE_UNCHANGED)
+ scan_type = pmadapter->scan_type;
+
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (pmadapter->fw_bands & BAND_A)
+ PRINTM(MINFO, "UserScan request for A Band channel %d!!\n",
+ channel);
+ else {
+ PRINTM(MERROR, "Scan in A band is not allowed!!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+
+ }
+ }
+
+ /* Prevent active scanning on a radar controlled channel */
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (wlan_11h_radar_detect_required(pmpriv, channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_BG) {
+ if (wlan_bg_scan_type_is_passive(pmpriv, channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ (pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
+ MTRUE;
+ } else {
+ (pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
+ MFALSE;
+ }
+
+ if (puser_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (t_u16) puser_scan_in->chan_list[chan_idx].scan_time;
+ } else {
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else if (*pfiltered_scan) {
+ scan_dur = pmadapter->specific_scan_time;
+ } else {
+ scan_dur = pmadapter->active_scan_time;
+ }
+ }
+
+ (pscan_chan_list + chan_idx)->min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ (pscan_chan_list + chan_idx)->max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chan_idx == 1)
+ && (puser_scan_in->chan_list[0].chan_number
+ == pmpriv->curr_bss_params.bss_descriptor.channel)) {
+ *pscan_current_only = MTRUE;
+ PRINTM(MINFO, "Scan: Scanning current channel only\n");
+ }
+
+ } else {
+ PRINTM(MINFO, "Scan: Creating full region channel list\n");
+ wlan_scan_create_channel_list(pmpriv, puser_scan_in, pscan_chan_list,
+ *pfiltered_scan);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ * Parse the data in the buffer for pointers to TLVs that can potentially
+ * be passed back in the response
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ptlv Pointer to the start of the TLV buffer to parse
+ * @param tlv_buf_size Size of the TLV buffer
+ * @param req_tlv_type Request TLV's type
+ * @param pptlv Output parameter: Pointer to the request TLV if found
+ *
+ * @return N/A
+ */
+static t_void
+wlan_ret_802_11_scan_get_tlv_ptrs(IN pmlan_adapter pmadapter,
+ IN MrvlIEtypes_Data_t * ptlv,
+ IN t_u32 tlv_buf_size,
+ IN t_u32 req_tlv_type,
+ OUT MrvlIEtypes_Data_t ** pptlv)
+{
+ MrvlIEtypes_Data_t *pcurrent_tlv;
+ t_u32 tlv_buf_left;
+ t_u32 tlv_type;
+ t_u32 tlv_len;
+
+ ENTER();
+
+ pcurrent_tlv = ptlv;
+ tlv_buf_left = tlv_buf_size;
+ *pptlv = MNULL;
+
+ PRINTM(MINFO, "SCAN_RESP: tlv_buf_size = %d\n", tlv_buf_size);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+
+ tlv_type = wlan_le16_to_cpu(pcurrent_tlv->header.type);
+ tlv_len = wlan_le16_to_cpu(pcurrent_tlv->header.len);
+
+ if (sizeof(ptlv->header) + tlv_len > tlv_buf_left) {
+ PRINTM(MERROR, "SCAN_RESP: TLV buffer corrupt\n");
+ break;
+ }
+
+ if (req_tlv_type == tlv_type) {
+ switch (tlv_type) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ PRINTM(MINFO, "SCAN_RESP: TSF Timestamp TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *) pcurrent_tlv;
+ break;
+ case TLV_TYPE_CHANNELBANDLIST:
+ PRINTM(MINFO, "SCAN_RESP: CHANNEL BAND LIST TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *) pcurrent_tlv;
+ break;
+ default:
+ PRINTM(MERROR, "SCAN_RESP: Unhandled TLV = %d\n", tlv_type);
+ /* Give up, this seems corrupted */
+ LEAVE();
+ return;
+ }
+ }
+
+ if (*pptlv) {
+ // HEXDUMP("SCAN_RESP: TLV Buf", (t_u8 *)*pptlv+4, tlv_len);
+ break;
+ }
+
+ tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
+ pcurrent_tlv = (MrvlIEtypes_Data_t *) (pcurrent_tlv->data + tlv_len);
+
+ } /* while */
+
+ LEAVE();
+}
+
+/**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a BSS probe
+ * response or beacon from the scan command. Record information as needed
+ * in the scan table BSSDescriptor_t for that entry.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pbss_entry Output parameter: Pointer to the BSS Entry
+ * @param pbeacon_info Pointer to the Beacon information
+ * @param bytes_left Number of bytes left to parse
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_interpret_bss_desc_with_ie(IN pmlan_adapter pmadapter,
+ OUT BSSDescriptor_t * pbss_entry,
+ IN t_u8 ** pbeacon_info, IN t_u32 * bytes_left)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_FhParamSet_t *pfh_param_set;
+ IEEEtypes_DsParamSet_t *pds_param_set;
+ IEEEtypes_CfParamSet_t *pcf_param_set;
+ IEEEtypes_IbssParamSet_t *pibss_param_set;
+ IEEEtypes_CapInfo_t *pcap_info;
+ WLAN_802_11_FIXED_IEs fixed_ie;
+ t_u8 *pcurrent_ptr;
+ t_u8 *prate;
+ t_u8 element_len;
+ t_u16 total_ie_len;
+ t_u8 bytes_to_copy;
+ t_u8 rate_size;
+ t_u16 beacon_size;
+ t_u8 found_data_rate_ie;
+ t_u32 bytes_left_for_current_beacon;
+ IEEEtypes_ERPInfo_t *perp_info;
+
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+ const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+
+ IEEEtypes_CountryInfoSet_t *pcountry_info;
+
+ ENTER();
+
+ found_data_rate_ie = MFALSE;
+ rate_size = 0;
+ beacon_size = 0;
+
+ if (*bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy(pmadapter, &beacon_size, *pbeacon_info, sizeof(beacon_size));
+ beacon_size = wlan_le16_to_cpu(beacon_size);
+ *bytes_left -= sizeof(beacon_size);
+ *pbeacon_info += sizeof(beacon_size);
+ }
+
+ if (!beacon_size || beacon_size > *bytes_left) {
+
+ *pbeacon_info += *bytes_left;
+ *bytes_left = 0;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration */
+ pcurrent_ptr = *pbeacon_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeacon_info += beacon_size;
+ *bytes_left -= beacon_size;
+
+ bytes_left_for_current_beacon = beacon_size;
+
+ if (bytes_left_for_current_beacon <
+ (MLAN_MAC_ADDR_LENGTH + sizeof(t_u8) + sizeof(WLAN_802_11_FIXED_IEs))) {
+ PRINTM(MERROR, "InterpretIE: Not enough bytes left\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(pmadapter, pbss_entry->mac_address, pcurrent_ptr,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO, "InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pbss_entry->mac_address[0], pbss_entry->mac_address[1],
+ pbss_entry->mac_address[2], pbss_entry->mac_address[3],
+ pbss_entry->mac_address[4], pbss_entry->mac_address[5]);
+
+ pcurrent_ptr += MLAN_MAC_ADDR_LENGTH;
+ bytes_left_for_current_beacon -= MLAN_MAC_ADDR_LENGTH;
+
+ /*
+ * Next 4 fields are RSSI (for legacy scan only), time stamp,
+ * beacon interval, and capability information
+ */
+ if (!pmadapter->ext_scan) {
+ /* RSSI is 1 byte long */
+ pbss_entry->rssi = (t_s32) (*pcurrent_ptr);
+ PRINTM(MINFO, "InterpretIE: RSSI=%02X\n", *pcurrent_ptr);
+ pcurrent_ptr += 1;
+ bytes_left_for_current_beacon -= 1;
+ }
+
+ /*
+ * The RSSI is not part of the beacon/probe response. After we have
+ * advanced pcurrent_ptr past the RSSI field, save the remaining
+ * data for use at the application layer
+ */
+ pbss_entry->pbeacon_buf = pcurrent_ptr;
+ pbss_entry->beacon_buf_size = bytes_left_for_current_beacon;
+
+ /* Time stamp is 8 bytes long */
+ memcpy(pmadapter, fixed_ie.time_stamp, pcurrent_ptr, 8);
+ memcpy(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8);
+ pcurrent_ptr += 8;
+ bytes_left_for_current_beacon -= 8;
+
+ /* Beacon interval is 2 bytes long */
+ memcpy(pmadapter, &fixed_ie.beacon_interval, pcurrent_ptr, 2);
+ pbss_entry->beacon_period = wlan_le16_to_cpu(fixed_ie.beacon_interval);
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Capability information is 2 bytes long */
+ memcpy(pmadapter, &fixed_ie.capabilities, pcurrent_ptr, 2);
+ PRINTM(MINFO, "InterpretIE: fixed_ie.capabilities=0x%X\n",
+ fixed_ie.capabilities);
+ fixed_ie.capabilities = wlan_le16_to_cpu(fixed_ie.capabilities);
+ pcap_info = (IEEEtypes_CapInfo_t *) & fixed_ie.capabilities;
+ memcpy(pmadapter, &pbss_entry->cap_info, pcap_info,
+ sizeof(IEEEtypes_CapInfo_t));
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Rest of the current buffer are IE's */
+ PRINTM(MINFO, "InterpretIE: IELength for this AP = %d\n",
+ bytes_left_for_current_beacon);
+
+ HEXDUMP("InterpretIE: IE info", (t_u8 *) pcurrent_ptr,
+ bytes_left_for_current_beacon);
+
+ if (pcap_info->privacy) {
+ PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
+ pbss_entry->privacy = Wlan802_11PrivFilter8021xWEP;
+ } else {
+ pbss_entry->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ if (pcap_info->ibss == 1) {
+ pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
+ } else {
+ pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
+ }
+
+ if (pcap_info->spectrum_mgmt == 1) {
+ PRINTM(MINFO, "InterpretIE: 11h- Spectrum Management "
+ "capability bit found\n");
+ pbss_entry->wlan_11h_bss_info.sensed_11h = 1;
+ }
+
+ /* Process variable IE */
+ while (bytes_left_for_current_beacon >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+
+ if (bytes_left_for_current_beacon < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left_for_current_beacon = 0;
+ continue;
+ }
+
+ switch (element_id) {
+
+ case SSID:
+ if (element_len > MRVDRV_MAX_SSID_LENGTH) {
+ bytes_left_for_current_beacon = 0;
+ continue;
+ }
+ pbss_entry->ssid.ssid_len = element_len;
+ memcpy(pmadapter, pbss_entry->ssid.ssid, (pcurrent_ptr + 2),
+ element_len);
+ PRINTM(MINFO, "InterpretIE: ssid: %-32s\n", pbss_entry->ssid.ssid);
+ break;
+
+ case SUPPORTED_RATES:
+ if (element_len > WLAN_SUPPORTED_RATES) {
+ bytes_left_for_current_beacon = 0;
+ continue;
+ }
+ memcpy(pmadapter, pbss_entry->data_rates, pcurrent_ptr + 2,
+ element_len);
+ memcpy(pmadapter, pbss_entry->supported_rates, pcurrent_ptr + 2,
+ element_len);
+ HEXDUMP("InterpretIE: SupportedRates:", pbss_entry->supported_rates,
+ element_len);
+ rate_size = element_len;
+ found_data_rate_ie = MTRUE;
+ break;
+
+ case FH_PARAM_SET:
+ pfh_param_set = (IEEEtypes_FhParamSet_t *) pcurrent_ptr;
+ pbss_entry->network_type_use = Wlan802_11FH;
+ memcpy(pmadapter, &pbss_entry->phy_param_set.fh_param_set,
+ pfh_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_FhParamSet_t)));
+ pbss_entry->phy_param_set.fh_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_FhParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ pbss_entry->phy_param_set.fh_param_set.dwell_time
+ =
+ wlan_le16_to_cpu(pbss_entry->phy_param_set.fh_param_set.
+ dwell_time);
+ break;
+
+ case DS_PARAM_SET:
+ pds_param_set = (IEEEtypes_DsParamSet_t *) pcurrent_ptr;
+
+ pbss_entry->network_type_use = Wlan802_11DS;
+ pbss_entry->channel = pds_param_set->current_chan;
+
+ memcpy(pmadapter, &pbss_entry->phy_param_set.ds_param_set,
+ pds_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_DsParamSet_t)));
+ pbss_entry->phy_param_set.ds_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_DsParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case CF_PARAM_SET:
+ pcf_param_set = (IEEEtypes_CfParamSet_t *) pcurrent_ptr;
+ memcpy(pmadapter, &pbss_entry->ss_param_set.cf_param_set,
+ pcf_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_CfParamSet_t)));
+ pbss_entry->ss_param_set.cf_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_CfParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case IBSS_PARAM_SET:
+ pibss_param_set = (IEEEtypes_IbssParamSet_t *) pcurrent_ptr;
+ pbss_entry->atim_window =
+ wlan_le16_to_cpu(pibss_param_set->atim_window);
+ memcpy(pmadapter, &pbss_entry->ss_param_set.ibss_param_set,
+ pibss_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_IbssParamSet_t)));
+ pbss_entry->ss_param_set.ibss_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_IbssParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ /* Handle Country Info IE */
+ case COUNTRY_INFO:
+ pcountry_info = (IEEEtypes_CountryInfoSet_t *) pcurrent_ptr;
+
+ if (pcountry_info->len < sizeof(pcountry_info->country_code) ||
+ (unsigned) (pcountry_info->len + 2) >
+ sizeof(IEEEtypes_CountryInfoFullSet_t)) {
+ PRINTM(MERROR,
+ "InterpretIE: 11D- Err "
+ "country_info len =%d min=%d max=%d\n",
+ pcountry_info->len, sizeof(pcountry_info->country_code),
+ sizeof(IEEEtypes_CountryInfoFullSet_t));
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(pmadapter, &pbss_entry->country_info,
+ pcountry_info, pcountry_info->len + 2);
+ HEXDUMP("InterpretIE: 11D- country_info:",
+ (t_u8 *) pcountry_info, (t_u32) (pcountry_info->len + 2));
+ break;
+
+ case ERP_INFO:
+ perp_info = (IEEEtypes_ERPInfo_t *) pcurrent_ptr;
+ pbss_entry->erp_flags = perp_info->erp_flags;
+ break;
+
+ case POWER_CONSTRAINT:
+ case POWER_CAPABILITY:
+ case TPC_REPORT:
+ case CHANNEL_SWITCH_ANN:
+ case QUIET:
+ case IBSS_DFS:
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ wlan_11h_process_bss_elem(pmadapter, &pbss_entry->wlan_11h_bss_info,
+ pcurrent_ptr);
+ break;
+ case EXTENDED_SUPPORTED_RATES:
+ /*
+ * Only process extended supported rate
+ * if data rate is already found.
+ * Data rate IE should come before
+ * extended supported rate IE
+ */
+ if (found_data_rate_ie) {
+ if ((element_len + rate_size) > WLAN_SUPPORTED_RATES) {
+ bytes_to_copy = (WLAN_SUPPORTED_RATES - rate_size);
+ } else {
+ bytes_to_copy = element_len;
+ }
+
+ prate = (t_u8 *) pbss_entry->data_rates;
+ prate += rate_size;
+ memcpy(pmadapter, prate, pcurrent_ptr + 2, bytes_to_copy);
+
+ prate = (t_u8 *) pbss_entry->supported_rates;
+ prate += rate_size;
+ memcpy(pmadapter, prate, pcurrent_ptr + 2, bytes_to_copy);
+ }
+ HEXDUMP("InterpretIE: ExtSupportedRates:",
+ pbss_entry->supported_rates, element_len + rate_size);
+ break;
+
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+
+ if (!memcmp
+ (pmadapter, pvendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(wpa_oui))) {
+ pbss_entry->pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ pbss_entry->wpa_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WPA_IE",
+ (t_u8 *) pbss_entry->pwpa_ie,
+ ((*(pbss_entry->pwpa_ie)).vend_hdr.len +
+ sizeof(IEEEtypes_Header_t)));
+ } else
+ if (!memcmp
+ (pmadapter, pvendor_ie->vend_hdr.oui, wmm_oui,
+ sizeof(wmm_oui))) {
+ if (total_ie_len == sizeof(IEEEtypes_WmmParameter_t)
+ || total_ie_len == sizeof(IEEEtypes_WmmInfo_t)) {
+
+ /*
+ * Only accept and copy the WMM IE if it matches
+ * the size expected for the WMM Info IE or the
+ * WMM Parameter IE.
+ */
+ memcpy(pmadapter, (t_u8 *) & pbss_entry->wmm_ie,
+ pcurrent_ptr, total_ie_len);
+ HEXDUMP("InterpretIE: Resp WMM_IE",
+ (t_u8 *) & pbss_entry->wmm_ie, total_ie_len);
+ }
+ }
+ break;
+ case RSN_IE:
+ pbss_entry->prsn_ie = (IEEEtypes_Generic_t *) pcurrent_ptr;
+ pbss_entry->rsn_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp RSN_IE", (t_u8 *) pbss_entry->prsn_ie,
+ (*(pbss_entry->prsn_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case WAPI_IE:
+ pbss_entry->pwapi_ie = (IEEEtypes_Generic_t *) pcurrent_ptr;
+ pbss_entry->wapi_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WAPI_IE", (t_u8 *) pbss_entry->pwapi_ie,
+ (*(pbss_entry->pwapi_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_CAPABILITY:
+ pbss_entry->pht_cap = (IEEEtypes_HTCap_t *) pcurrent_ptr;
+ pbss_entry->ht_cap_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE", (t_u8 *) pbss_entry->pht_cap,
+ (*(pbss_entry->pht_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_OPERATION:
+ pbss_entry->pht_info = (IEEEtypes_HTInfo_t *) pcurrent_ptr;
+ pbss_entry->ht_info_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTINFO_IE",
+ (t_u8 *) pbss_entry->pht_info,
+ (*(pbss_entry->pht_info)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case BSSCO_2040:
+ pbss_entry->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *) pcurrent_ptr;
+ pbss_entry->bss_co_2040_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp 2040BSSCOEXISTANCE_IE",
+ (t_u8 *) pbss_entry->pbss_co_2040,
+ (*(pbss_entry->pbss_co_2040)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXT_CAPABILITY:
+ pbss_entry->pext_cap = (IEEEtypes_ExtCap_t *) pcurrent_ptr;
+ pbss_entry->ext_cap_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp EXTCAP_IE",
+ (t_u8 *) pbss_entry->pext_cap,
+ (*(pbss_entry->pext_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case OVERLAPBSSSCANPARAM:
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *) pcurrent_ptr;
+ pbss_entry->overlap_bss_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE",
+ (t_u8 *) pbss_entry->poverlap_bss_scan_param,
+ (*(pbss_entry->poverlap_bss_scan_param)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ }
+
+ pcurrent_ptr += element_len + 2;
+
+ /* Need to account for IE ID and IE Len */
+ bytes_left_for_current_beacon -= (element_len + 2);
+
+ } /* while (bytes_left_for_current_beacon > 2) */
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Adjust ie's position in BSSDescriptor_t
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_entry A pointer to BSSDescriptor_t structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_adjust_ie_in_bss_entry(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_entry)
+{
+ ENTER();
+ if (pbss_entry->pbeacon_buf) {
+ if (pbss_entry->pwpa_ie) {
+ pbss_entry->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->wpa_offset);
+ }
+ if (pbss_entry->prsn_ie) {
+ pbss_entry->prsn_ie = (IEEEtypes_Generic_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->rsn_offset);
+ }
+ if (pbss_entry->pwapi_ie) {
+ pbss_entry->pwapi_ie = (IEEEtypes_Generic_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->wapi_offset);
+ }
+ if (pbss_entry->pht_cap) {
+ pbss_entry->pht_cap = (IEEEtypes_HTCap_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->ht_cap_offset);
+ }
+ if (pbss_entry->pht_info) {
+ pbss_entry->pht_info = (IEEEtypes_HTInfo_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->ht_info_offset);
+ }
+ if (pbss_entry->pbss_co_2040) {
+ pbss_entry->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->bss_co_2040_offset);
+ }
+ if (pbss_entry->pext_cap) {
+ pbss_entry->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->ext_cap_offset);
+ }
+ if (pbss_entry->poverlap_bss_scan_param) {
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->overlap_bss_offset);
+ }
+ } else {
+ pbss_entry->pwpa_ie = MNULL;
+ pbss_entry->wpa_offset = 0;
+ pbss_entry->prsn_ie = MNULL;
+ pbss_entry->rsn_offset = 0;
+ pbss_entry->pwapi_ie = MNULL;
+ pbss_entry->wapi_offset = 0;
+ pbss_entry->pht_cap = MNULL;
+ pbss_entry->ht_cap_offset = 0;
+ pbss_entry->pht_info = MNULL;
+ pbss_entry->ht_info_offset = 0;
+ pbss_entry->pbss_co_2040 = MNULL;
+ pbss_entry->bss_co_2040_offset = 0;
+ pbss_entry->pext_cap = MNULL;
+ pbss_entry->ext_cap_offset = 0;
+ pbss_entry->poverlap_bss_scan_param = MNULL;
+ pbss_entry->overlap_bss_offset = 0;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Store a beacon or probe response for a BSS returned in the scan
+ *
+ * Store a new scan response or an update for a previous scan response. New
+ * entries need to verify that they do not exceed the total amount of
+ * memory allocated for the table.
+
+ * Replacement entries need to take into consideration the amount of space
+ * currently allocated for the beacon/probe response and adjust the entry
+ * as needed.
+ *
+ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ * for an entry in case it is a beacon since a probe response for the
+ * network will by larger per the standard. This helps to reduce the
+ * amount of memory copying to fit a new probe response into an entry
+ * already occupied by a network's previously stored beacon.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param beacon_idx Index in the scan table to store this entry; may be
+ * replacing an older duplicate entry for this BSS
+ * @param num_of_ent Number of entries currently in the table
+ * @param pnew_beacon Pointer to the new beacon/probe response to save
+ *
+ * @return N/A
+ */
+static t_void
+wlan_ret_802_11_scan_store_beacon(IN mlan_private * pmpriv,
+ IN t_u32 beacon_idx,
+ IN t_u32 num_of_ent,
+ IN BSSDescriptor_t * pnew_beacon)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 *pbcn_store;
+ t_u32 new_bcn_size;
+ t_u32 old_bcn_size;
+ t_u32 bcn_space;
+ t_u32 adj_idx;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *tmp_buf;
+ t_u16 bcn_size = 0;
+ t_u32 bcn_offset = 0;
+
+ ENTER();
+
+ if (pmadapter->pscan_table[beacon_idx].pbeacon_buf) {
+
+ new_bcn_size = pnew_beacon->beacon_buf_size;
+ old_bcn_size = pmadapter->pscan_table[beacon_idx].beacon_buf_size;
+ bcn_space = pmadapter->pscan_table[beacon_idx].beacon_buf_size_max;
+ pbcn_store = pmadapter->pscan_table[beacon_idx].pbeacon_buf;
+
+ /* Set the max to be the same as current entry unless changed below */
+ pnew_beacon->beacon_buf_size_max = bcn_space;
+
+ if (new_bcn_size == old_bcn_size) {
+ /*
+ * Beacon is the same size as the previous entry.
+ * Replace the previous contents with the scan result
+ */
+ memcpy(pmadapter, pbcn_store,
+ pnew_beacon->pbeacon_buf, pnew_beacon->beacon_buf_size);
+
+ } else if (new_bcn_size <= bcn_space) {
+ /*
+ * New beacon size will fit in the amount of space
+ * we have previously allocated for it
+ */
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
+ new_bcn_size);
+
+ /*
+ * If the old beacon size was less than the maximum
+ * we had allotted for the entry, and the new entry
+ * is even smaller, reset the max size to the old beacon
+ * entry and compress the storage space (leaving a new
+ * pad space of (old_bcn_size - new_bcn_size).
+ */
+ if (old_bcn_size < bcn_space && new_bcn_size <= old_bcn_size) {
+ /*
+ * Old Beacon size is smaller than the allotted storage size.
+ * Shrink the allotted storage space.
+ */
+ PRINTM(MINFO, "AppControl: Smaller Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This cleans up any unused
+ * space the old larger beacon was using in the buffer
+ */
+ memmove(pmadapter,
+ (void *) ((t_ptr) pbcn_store + (t_ptr) old_bcn_size),
+ (void *) ((t_ptr) pbcn_store + (t_ptr) bcn_space),
+ (t_u32) ((t_ptr) pmadapter->pbcn_buf_end -
+ ((t_ptr) pbcn_store + (t_ptr) bcn_space)));
+
+ /*
+ * Decrement the end pointer by the difference between
+ * the old larger size and the new smaller size since
+ * we are using less space due to the new beacon being
+ * smaller
+ */
+ pmadapter->pbcn_buf_end -= (bcn_space - old_bcn_size);
+
+ /* Set the maximum storage size to the old beacon size */
+ pnew_beacon->beacon_buf_size_max = old_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf >
+ pbcn_store) {
+ pmadapter->pscan_table[adj_idx].pbeacon_buf -=
+ (bcn_space - old_bcn_size);
+ wlan_adjust_ie_in_bss_entry(pmpriv,
+ &pmadapter->
+ pscan_table[adj_idx]);
+ }
+ }
+ }
+ } else if (pmadapter->pbcn_buf_end + (new_bcn_size - bcn_space)
+ < (pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
+ /*
+ * Beacon is larger than space previously allocated (bcn_space)
+ * and there is enough space left in the beaconBuffer to store
+ * the additional data
+ */
+ PRINTM(MINFO, "AppControl: Larger Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This moves the data for
+ * the beacons after this further in memory to
+ * make space for the new larger beacon we are
+ * about to copy in.
+ */
+ memmove(pmadapter,
+ (void *) ((t_ptr) pbcn_store + (t_ptr) new_bcn_size),
+ (void *) ((t_ptr) pbcn_store + (t_ptr) bcn_space),
+ (t_u32) ((t_ptr) pmadapter->pbcn_buf_end -
+ ((t_ptr) pbcn_store + (t_ptr) bcn_space)));
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
+ new_bcn_size);
+
+ /* Move the beacon end pointer by the amount of new beacon data we
+ are adding */
+ pmadapter->pbcn_buf_end += (new_bcn_size - bcn_space);
+
+ /*
+ * This entry is bigger than the allotted max space
+ * previously reserved. Increase the max space to
+ * be equal to the new beacon size
+ */
+ pnew_beacon->beacon_buf_size_max = new_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf > pbcn_store) {
+ pmadapter->pscan_table[adj_idx].pbeacon_buf
+ += (new_bcn_size - bcn_space);
+ wlan_adjust_ie_in_bss_entry(pmpriv,
+ &pmadapter->
+ pscan_table[adj_idx]);
+ }
+ }
+ } else {
+ /*
+ * Beacon is larger than the previously allocated space, but
+ * there is not enough free space to store the additional data
+ */
+ PRINTM(MERROR,
+ "AppControl: Failed: Larger Duplicate Beacon (%d),"
+ " old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure, keep old beacon intact */
+ pnew_beacon->beacon_buf_size = old_bcn_size;
+ if (pnew_beacon->pwpa_ie)
+ pnew_beacon->wpa_offset =
+ pmadapter->pscan_table[beacon_idx].wpa_offset;
+ if (pnew_beacon->prsn_ie)
+ pnew_beacon->rsn_offset =
+ pmadapter->pscan_table[beacon_idx].rsn_offset;
+ if (pnew_beacon->pwapi_ie)
+ pnew_beacon->wapi_offset =
+ pmadapter->pscan_table[beacon_idx].wapi_offset;
+ if (pnew_beacon->pht_cap)
+ pnew_beacon->ht_cap_offset =
+ pmadapter->pscan_table[beacon_idx].ht_cap_offset;
+ if (pnew_beacon->pht_info)
+ pnew_beacon->ht_info_offset =
+ pmadapter->pscan_table[beacon_idx].ht_info_offset;
+ if (pnew_beacon->pbss_co_2040)
+ pnew_beacon->bss_co_2040_offset =
+ pmadapter->pscan_table[beacon_idx].bss_co_2040_offset;
+ if (pnew_beacon->pext_cap)
+ pnew_beacon->ext_cap_offset =
+ pmadapter->pscan_table[beacon_idx].ext_cap_offset;
+ if (pnew_beacon->poverlap_bss_scan_param)
+ pnew_beacon->overlap_bss_offset =
+ pmadapter->pscan_table[beacon_idx].overlap_bss_offset;
+ }
+ /* Point the new entry to its permanent storage space */
+ pnew_beacon->pbeacon_buf = pbcn_store;
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+ } else {
+ if ((pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD > (pmadapter->bcn_buf +
+ pmadapter->bcn_buf_size)) &&
+ (pmadapter->bcn_buf_size < MAX_SCAN_BEACON_BUFFER)) {
+ /* no space for this entry, realloc bcn buffer */
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ pmadapter->bcn_buf_size +
+ DEFAULT_SCAN_BEACON_BUFFER,
+ MLAN_MEM_DEF,
+ (t_u8 **) & tmp_buf);
+ if ((ret == MLAN_STATUS_SUCCESS) && (tmp_buf)) {
+ PRINTM(MCMND,
+ "Realloc Beacon buffer, old size=%d, new_size=%d\n",
+ pmadapter->bcn_buf_size,
+ pmadapter->bcn_buf_size + DEFAULT_SCAN_BEACON_BUFFER);
+ bcn_size = pmadapter->pbcn_buf_end - pmadapter->bcn_buf;
+ memcpy(pmadapter, tmp_buf, pmadapter->bcn_buf, bcn_size);
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ bcn_offset =
+ pmadapter->pscan_table[adj_idx].pbeacon_buf -
+ pmadapter->bcn_buf;
+ pmadapter->pscan_table[adj_idx].pbeacon_buf =
+ tmp_buf + bcn_offset;
+ wlan_adjust_ie_in_bss_entry(pmpriv,
+ &pmadapter->
+ pscan_table[adj_idx]);
+ }
+ pmadapter->pbcn_buf_end = tmp_buf + bcn_size;
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->bcn_buf);
+ pmadapter->bcn_buf = tmp_buf;
+ pmadapter->bcn_buf_size += DEFAULT_SCAN_BEACON_BUFFER;
+ }
+ }
+ /*
+ * No existing beacon data exists for this entry, check to see
+ * if we can fit it in the remaining space
+ */
+ if (pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD < (pmadapter->bcn_buf +
+ pmadapter->bcn_buf_size)) {
+
+ /*
+ * Copy the beacon buffer data from the local entry to the
+ * adapter dev struct buffer space used to store the raw
+ * beacon data for each entry in the scan table
+ */
+ memcpy(pmadapter, pmadapter->pbcn_buf_end, pnew_beacon->pbeacon_buf,
+ pnew_beacon->beacon_buf_size);
+
+ /* Update the beacon ptr to point to the table save area */
+ pnew_beacon->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pnew_beacon->beacon_buf_size_max = (pnew_beacon->beacon_buf_size
+ + SCAN_BEACON_ENTRY_PAD);
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+
+ /* Increment the end pointer by the size reserved */
+ pmadapter->pbcn_buf_end += pnew_beacon->beacon_buf_size_max;
+
+ PRINTM(MINFO, "AppControl: Beacon[%02d] sz=%03d,"
+ " used = %04d, left = %04d\n",
+ beacon_idx,
+ pnew_beacon->beacon_buf_size,
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf),
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+ } else {
+ /*
+ * No space for new beacon
+ */
+ PRINTM(MCMND, "AppControl: No space beacon (%d): "
+ "%02x:%02x:%02x:%02x:%02x:%02x; sz=%03d, left=%03d\n",
+ beacon_idx,
+ pnew_beacon->mac_address[0], pnew_beacon->mac_address[1],
+ pnew_beacon->mac_address[2], pnew_beacon->mac_address[3],
+ pnew_beacon->mac_address[4], pnew_beacon->mac_address[5],
+ pnew_beacon->beacon_buf_size,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure; clear storage records for this bcn */
+ pnew_beacon->pbeacon_buf = MNULL;
+ pnew_beacon->beacon_buf_size = 0;
+ pnew_beacon->beacon_buf_size_max = 0;
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Restore a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_restore_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+
+ ENTER();
+
+ if (pmpriv->pcurr_bcn_buf &&
+ ((pmadapter->pbcn_buf_end + pmpriv->curr_bcn_size) <
+ (pmadapter->bcn_buf + pmadapter->bcn_buf_size))) {
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmpriv->curr_bcn_buf_lock);
+
+ /* restore the current beacon buffer */
+ memcpy(pmadapter, pmadapter->pbcn_buf_end, pmpriv->pcurr_bcn_buf,
+ pmpriv->curr_bcn_size);
+ pcurr_bss->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pcurr_bss->beacon_buf_size = pmpriv->curr_bcn_size;
+ pmadapter->pbcn_buf_end += pmpriv->curr_bcn_size;
+
+ /* adjust the pointers in the current bss descriptor */
+ if (pcurr_bss->pwpa_ie) {
+ pcurr_bss->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->wpa_offset);
+ }
+ if (pcurr_bss->prsn_ie) {
+ pcurr_bss->prsn_ie = (IEEEtypes_Generic_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->rsn_offset);
+ }
+ if (pcurr_bss->pht_cap) {
+ pcurr_bss->pht_cap = (IEEEtypes_HTCap_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ht_cap_offset);
+ }
+
+ if (pcurr_bss->pht_info) {
+ pcurr_bss->pht_info = (IEEEtypes_HTInfo_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ht_info_offset);
+ }
+
+ if (pcurr_bss->pbss_co_2040) {
+ pcurr_bss->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->bss_co_2040_offset);
+ }
+
+ if (pcurr_bss->pext_cap) {
+ pcurr_bss->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ext_cap_offset);
+ }
+
+ if (pcurr_bss->poverlap_bss_scan_param) {
+ pcurr_bss->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->overlap_bss_offset);
+ }
+
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+
+ PRINTM(MINFO, "current beacon restored %d\n", pmpriv->curr_bcn_size);
+ } else {
+ PRINTM(MWARN, "curr_bcn_buf not saved or bcn_buf has no space\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Post process the scan table after a new scan command has completed
+ *
+ * Inspect each entry of the scan table and try to find an entry that
+ * matches our current associated/joined network from the scan. If
+ * one is found, update the stored copy of the BSSDescriptor for our
+ * current network.
+ *
+ * Debug dump the current scan table contents if compiled accordingly.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_scan_process_results(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 j;
+ t_u32 i;
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+
+ j = wlan_find_ssid_in_list(pmpriv,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, pmpriv->bss_mode);
+
+ if (j >= 0) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+ pmpriv->curr_bss_params.bss_descriptor.pwpa_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.prsn_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pwapi_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_cap_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_info = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_info_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbss_co_2040 = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pext_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.overlap_bss_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size_max = 0;
+
+ PRINTM(MINFO, "Found current ssid/bssid in list @ index #%d\n", j);
+ /* Make a copy of current BSSID descriptor */
+ memcpy(pmadapter, &pmpriv->curr_bss_params.bss_descriptor,
+ &pmadapter->pscan_table[j],
+ sizeof(pmpriv->curr_bss_params.bss_descriptor));
+
+ wlan_save_curr_bcn(pmpriv);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+ } else {
+ wlan_restore_curr_bcn(pmpriv);
+ }
+ }
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++)
+ PRINTM(MINFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+ "RSSI[%03d], SSID[%s]\n",
+ i,
+ pmadapter->pscan_table[i].mac_address[0],
+ pmadapter->pscan_table[i].mac_address[1],
+ pmadapter->pscan_table[i].mac_address[2],
+ pmadapter->pscan_table[i].mac_address[3],
+ pmadapter->pscan_table[i].mac_address[4],
+ pmadapter->pscan_table[i].mac_address[5],
+ (t_s32) pmadapter->pscan_table[i].rssi,
+ pmadapter->pscan_table[i].ssid.ssid);
+
+ /*
+ * Prepares domain info from scan table and downloads the
+ * domain info command to the FW.
+ */
+ wlan_11d_prepare_dnld_domain_info_cmd(pmpriv);
+
+ LEAVE();
+}
+
+/**
+ * @brief Convert radio type scan parameter to a band config used in join cmd
+ *
+ * @param radio_type Scan parameter indicating the radio used for a channel
+ * in a scan command.
+ *
+ * @return Band type conversion of scanBand used in join/assoc cmds
+ *
+ */
+static t_u8
+radio_type_to_band(t_u8 radio_type)
+{
+ t_u8 ret_band;
+
+ switch (radio_type) {
+ case HostCmd_SCAN_RADIO_TYPE_A:
+ ret_band = BAND_A;
+ break;
+ case HostCmd_SCAN_RADIO_TYPE_BG:
+ default:
+ ret_band = BAND_G;
+ break;
+ }
+
+ return ret_band;
+}
+
+/**
+ * @brief Delete a specific indexed entry from the scan table.
+ *
+ * Delete the scan table entry indexed by table_idx. Compact the remaining
+ * entries and adjust any buffering of beacon/probe response data
+ * if needed.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param table_idx Scan table entry index to delete from the table
+ *
+ * @return N/A
+ *
+ * @pre table_idx must be an index to a valid entry
+ */
+static t_void
+wlan_scan_delete_table_entry(IN mlan_private * pmpriv, IN t_s32 table_idx)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 del_idx;
+ t_u32 beacon_buf_adj;
+ t_u8 *pbeacon_buf;
+
+ ENTER();
+
+ /*
+ * Shift the saved beacon buffer data for the scan table back over the
+ * entry being removed. Update the end of buffer pointer. Save the
+ * deleted buffer allocation size for pointer adjustments for entries
+ * compacted after the deleted index.
+ */
+ beacon_buf_adj = pmadapter->pscan_table[table_idx].beacon_buf_size_max;
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
+ table_idx, beacon_buf_adj);
+
+ /* Check if the table entry had storage allocated for its beacon */
+ if (beacon_buf_adj) {
+ pbeacon_buf = pmadapter->pscan_table[table_idx].pbeacon_buf;
+
+ /*
+ * Remove the entry's buffer space, decrement the table end pointer
+ * by the amount we are removing
+ */
+ pmadapter->pbcn_buf_end -= beacon_buf_adj;
+
+ PRINTM(MINFO,
+ "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
+ table_idx,
+ pbeacon_buf,
+ pbeacon_buf + beacon_buf_adj,
+ pmadapter->pbcn_buf_end - pbeacon_buf);
+
+ /*
+ * Compact data storage. Copy all data after the deleted entry's
+ * end address (pbeacon_buf + beacon_buf_adj) back to the original
+ * start address (pbeacon_buf).
+ *
+ * Scan table entries affected by the move will have their entry
+ * pointer adjusted below.
+ *
+ * Use memmove since the dest/src memory regions overlap.
+ */
+ memmove(pmadapter, pbeacon_buf,
+ (void *) ((t_ptr) pbeacon_buf + (t_ptr) beacon_buf_adj),
+ (t_u32) ((t_ptr) pmadapter->pbcn_buf_end -
+ (t_ptr) pbeacon_buf));
+ }
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, num_in_scan_table = %d\n",
+ table_idx, pmadapter->num_in_scan_table);
+
+ /* Shift all of the entries after the table_idx back by one, compacting the
+ table and removing the requested entry */
+ for (del_idx = table_idx; (del_idx + 1) < pmadapter->num_in_scan_table;
+ del_idx++) {
+ /* Copy the next entry over this one */
+ memcpy(pmadapter, pmadapter->pscan_table + del_idx,
+ pmadapter->pscan_table + del_idx + 1, sizeof(BSSDescriptor_t));
+
+ /*
+ * Adjust this entry's pointer to its beacon buffer based on the
+ * removed/compacted entry from the deleted index. Don't decrement
+ * if the buffer pointer is MNULL (no data stored for this entry).
+ */
+ if (pmadapter->pscan_table[del_idx].pbeacon_buf) {
+ pmadapter->pscan_table[del_idx].pbeacon_buf -= beacon_buf_adj;
+ if (pmadapter->pscan_table[del_idx].pwpa_ie) {
+ pmadapter->pscan_table[del_idx].pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].wpa_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].prsn_ie) {
+ pmadapter->pscan_table[del_idx].prsn_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].rsn_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pwapi_ie) {
+ pmadapter->pscan_table[del_idx].pwapi_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].wapi_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pht_cap) {
+ pmadapter->pscan_table[del_idx].pht_cap =
+ (IEEEtypes_HTCap_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].pht_info) {
+ pmadapter->pscan_table[del_idx].pht_info =
+ (IEEEtypes_HTInfo_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ht_info_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pbss_co_2040) {
+ pmadapter->pscan_table[del_idx].pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ bss_co_2040_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pext_cap) {
+ pmadapter->pscan_table[del_idx].pext_cap =
+ (IEEEtypes_ExtCap_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ext_cap_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].poverlap_bss_scan_param) {
+ pmadapter->pscan_table[del_idx].poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *) (pmadapter->
+ pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->
+ pscan_table[del_idx].
+ overlap_bss_offset);
+ }
+
+ }
+ }
+
+ /* The last entry is invalid now that it has been deleted or moved back */
+ memset(pmadapter, pmadapter->pscan_table + pmadapter->num_in_scan_table - 1,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ pmadapter->num_in_scan_table--;
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all occurrences of a given SSID from the scan table
+ *
+ * Iterate through the scan table and delete all entries that match a given
+ * SSID. Compact the remaining scan table entries.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdel_ssid Pointer to an SSID to be used in deleting all
+ * matching SSIDs from the scan table
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_scan_delete_ssid_table_entry(IN mlan_private * pmpriv,
+ IN mlan_802_11_ssid * pdel_ssid)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_s32 table_idx;
+
+ ENTER();
+
+ PRINTM(MINFO, "Scan: Delete Ssid Entry: %-32s\n", pdel_ssid->ssid);
+
+ /* If the requested SSID is found in the table, delete it. Then keep
+ searching the table for multiple entries for the SSID until no more are
+ found */
+ while ((table_idx = wlan_find_ssid_in_list(pmpriv,
+ pdel_ssid,
+ MNULL,
+ MLAN_BSS_MODE_AUTO)) >= 0) {
+ PRINTM(MINFO, "Scan: Delete SSID Entry: Found Idx = %d\n", table_idx);
+ ret = MLAN_STATUS_SUCCESS;
+ wlan_scan_delete_table_entry(pmpriv, table_idx);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+ * WEP WPA WPA2 ad-hoc encrypt Network
+ * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
+ * 0 0 0 0 NONE 0 0 0 yes No security
+ * 0 1 0 0 x 1x 1 x yes WPA (disable HT if no AES)
+ * 0 0 1 0 x 1x x 1 yes WPA2 (disable HT if no AES)
+ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
+ * 1 0 0 0 NONE 1 0 0 yes Static WEP (disable HT)
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ * @param pmpriv A pointer to mlan_private
+ * @param index Index in scan table to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in ScanTable, or negative value if error
+ */
+t_s32
+wlan_is_network_compatible(IN mlan_private * pmpriv,
+ IN t_u32 index, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ pbss_desc = &pmadapter->pscan_table[index];
+ pbss_desc->disable_11n = MFALSE;
+
+ /* Don't check for compatibility if roaming */
+ if ((pmpriv->media_connected == MTRUE)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && (pbss_desc->bss_mode == MLAN_BSS_MODE_INFRA)) {
+ LEAVE();
+ return index;
+ }
+
+ if (pbss_desc->wlan_11h_bss_info.chan_switch_ann.element_id ==
+ CHANNEL_SWITCH_ANN) {
+ PRINTM(MINFO, "Don't connect to AP with CHANNEL_SWITCH_ANN IE.\n");
+ LEAVE();
+ return -1;
+ }
+
+ if (pmpriv->wps.session_enable == MTRUE) {
+ PRINTM(MINFO, "Return success directly in WPS period\n");
+ LEAVE();
+ return index;
+ }
+
+ if ((pbss_desc->bss_mode == mode) &&
+ (pmpriv->sec_info.ewpa_enabled == MTRUE)) {
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
+ ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)
+ && !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+
+ if (is_wpa_oui_present
+ (pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP)
+ || is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else {
+ PRINTM(MINFO, "ewpa_enabled: Ignore none WPA/WPA2 AP\n");
+ LEAVE();
+ return -1;
+ }
+ }
+
+ if (pmpriv->sec_info.wapi_enabled &&
+ (pbss_desc->pwapi_ie &&
+ ((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE))) {
+ PRINTM(MINFO, "Return success for WAPI AP\n");
+ LEAVE();
+ return index;
+ }
+
+ if (pbss_desc->bss_mode == mode) {
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && !pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE &&
+ !pbss_desc->privacy) {
+ /* No security */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && !pmpriv->adhoc_aes_enabled && pbss_desc->privacy) {
+ /* Static WEP enabled */
+ PRINTM(MINFO, "Disable 11n in WEP mode\n");
+ pbss_desc->disable_11n = MTRUE;
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))
+ && !pmpriv->adhoc_aes_enabled
+ /*
+ * Privacy bit may NOT be set in some APs like LinkSys WRT54G
+ * && pbss_desc->privacy
+ */
+ ) {
+ /* WPA enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n", index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+ if (is_wpa_oui_present
+ (pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && pmpriv->sec_info.wpa2_enabled
+ && ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))
+ && !pmpriv->adhoc_aes_enabled
+ /*
+ * Privacy bit may NOT be set in some APs like LinkSys WRT54G
+ * && pbss_desc->privacy
+ */
+ ) {
+ /* WPA2 enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n", index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+ if (is_rsn_oui_present
+ (pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE
+ && pbss_desc->privacy) {
+ /* Ad-hoc AES enabled */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && !pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode != MLAN_ENCRYPTION_MODE_NONE
+ && pbss_desc->privacy) {
+ /* Dynamic WEP enabled */
+ PRINTM(MINFO, "wlan_is_network_compatible() dynamic WEP: index=%d "
+ "wpa_ie=%#x rsn_ie=%#x EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0, pmpriv->sec_info.encryption_mode,
+ pbss_desc->privacy);
+ LEAVE();
+ return index;
+ }
+
+ /* Security doesn't match */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ LEAVE();
+ return -1;
+ }
+
+ /* Mode doesn't match */
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief Internal function used to flush the scan list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_flush_scan_table(IN pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Flushing scan table\n");
+
+ memset(pmadapter, pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->num_in_scan_table = 0;
+
+ memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Internal function used to start a scan based on an input config
+ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param puser_scan_in Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return MLAN_STATUS_SUCCESS or < 0 if error
+ */
+mlan_status
+wlan_scan_networks(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN const wlan_user_scan_cfg * puser_scan_in)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ wlan_scan_cmd_config_tlv *pscan_cfg_out = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list_out;
+ t_u32 buf_size;
+ ChanScanParamSet_t *pscan_chan_list;
+
+ t_u8 keep_previous_scan;
+ t_u8 filtered_scan;
+ t_u8 scan_current_chan_only;
+ t_u8 max_chan_per_scan;
+
+ ENTER();
+
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(wlan_scan_cmd_config_tlv), MLAN_MEM_DEF,
+ (t_u8 **) & pscan_cfg_out);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg_out) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
+ (t_u8 **) & pscan_chan_list);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
+ PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_cfg_out);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, pscan_chan_list, 0x00, buf_size);
+ memset(pmadapter, pscan_cfg_out, 0x00, sizeof(wlan_scan_cmd_config_tlv));
+
+ keep_previous_scan = MFALSE;
+
+ ret = wlan_scan_setup_scan_config(pmpriv,
+ puser_scan_in,
+ &pscan_cfg_out->config,
+ &pchan_list_out,
+ pscan_chan_list,
+ &max_chan_per_scan,
+ &filtered_scan, &scan_current_chan_only);
+ if (ret != MLAN_STATUS_SUCCESS) {
+
+ PRINTM(MERROR, "Failed to setup scan config\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_cfg_out);
+ if (pscan_chan_list)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_chan_list);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (puser_scan_in) {
+ keep_previous_scan = puser_scan_in->keep_previous_scan;
+ }
+
+ if (keep_previous_scan == MFALSE) {
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ }
+
+ ret = wlan_scan_channel_list(pmpriv,
+ pioctl_buf,
+ max_chan_per_scan,
+ filtered_scan,
+ &pscan_cfg_out->config,
+ pchan_list_out, pscan_chan_list);
+
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)) {
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pmadapter->pext_scan_ioctl_req = pioctl_req;
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MTRUE;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_cfg_out);
+
+ if (pscan_chan_list)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_chan_list);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
+ * struct to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_801_11_SCAN structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_scan(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN *pscan_cmd = &pcmd->params.scan;
+ wlan_scan_cmd_config *pscan_cfg;
+
+ ENTER();
+
+ pscan_cfg = (wlan_scan_cmd_config *) pdata_buf;
+
+ /* Set fixed field variables in scan command */
+ pscan_cmd->bss_mode = pscan_cfg->bss_mode;
+ memcpy(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid,
+ sizeof(pscan_cmd->bssid));
+ memcpy(pmpriv->adapter, pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf,
+ pscan_cfg->tlv_buf_len);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(pscan_cmd->bss_mode)
+ + sizeof(pscan_cmd->bssid)
+ + pscan_cfg->tlv_buf_len
+ + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of scan
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-------------------------------------------------------------.
+ * | Header (4 * sizeof(t_u16)): Standard command response hdr |
+ * .-------------------------------------------------------------.
+ * | BufSize (t_u16) : sizeof the BSS Description data |
+ * .-------------------------------------------------------------.
+ * | NumOfSet (t_u8) : Number of BSS Descs returned |
+ * .-------------------------------------------------------------.
+ * | BSSDescription data (variable, size given in BufSize) |
+ * .-------------------------------------------------------------.
+ * | TLV data (variable, size calculated using Header->Size, |
+ * | BufSize and sizeof the fixed fields above) |
+ * .-------------------------------------------------------------.
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_scan(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_802_11_SCAN_RSP *pscan_rsp = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ MrvlIEtypes_Data_t *ptlv;
+ MrvlIEtypes_TsfTimestamp_t *ptsf_tlv = MNULL;
+ t_u8 *pbss_info;
+ t_u32 scan_resp_size;
+ t_u32 bytes_left;
+ t_u32 num_in_table;
+ t_u32 bss_idx;
+ t_u32 idx;
+ t_u32 tlv_buf_size;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv = MNULL;
+ ChanBandParamSet_t *pchan_band;
+ t_u8 band;
+ t_u8 is_bgscan_resp;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ is_bgscan_resp = (resp->command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ if (is_bgscan_resp) {
+ pscan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
+ } else {
+ pscan_rsp = &resp->params.scan_resp;
+ }
+
+ if (pscan_rsp->number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR, "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+ pscan_rsp->number_of_sets);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
+ PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
+
+ scan_resp_size = resp->size;
+
+ PRINTM(MINFO, "SCAN_RESP: returned %d APs before parsing\n",
+ pscan_rsp->number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ pbss_info = pscan_rsp->bss_desc_and_tlv_buffer;
+
+ /*
+ * The size of the TLV buffer is equal to the entire command response
+ * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bss_descript_size as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlv_buf_size = scan_resp_size - (bytes_left
+ + sizeof(pscan_rsp->bss_descript_size)
+ + sizeof(pscan_rsp->number_of_sets)
+ + S_DS_GEN);
+
+ ptlv =
+ (MrvlIEtypes_Data_t *) (pscan_rsp->bss_desc_and_tlv_buffer +
+ bytes_left);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
+ ptlv,
+ tlv_buf_size,
+ TLV_TYPE_TSFTIMESTAMP,
+ (MrvlIEtypes_Data_t **) & ptsf_tlv);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
+ ptlv,
+ tlv_buf_size,
+ TLV_TYPE_CHANNELBANDLIST,
+ (MrvlIEtypes_Data_t **) & pchan_band_tlv);
+
+ /*
+ * Process each scan response returned (pscan_rsp->number_of_sets). Save
+ * the information in the bss_new_entry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF, (t_u8 **) & bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0; idx < pscan_rsp->number_of_sets && bytes_left; idx++) {
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if (wlan_interpret_bss_desc_with_ie(pmadapter,
+ bss_new_entry,
+ &pbss_info,
+ &bytes_left) ==
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss_new_entry->mac_address[0], bss_new_entry->mac_address[1],
+ bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
+ bss_new_entry->mac_address[4],
+ bss_new_entry->mac_address[5]);
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(pmadapter, bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bss_idx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len)
+ && (!memcmp(pmadapter, bss_new_entry->ssid.ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ PRINTM(MINFO, "SCAN_RESP: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to the last entry */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST) {
+ bss_idx--;
+ } else {
+ num_in_table++;
+ }
+ }
+
+ /*
+ * Save the beacon/probe response returned for later application
+ * retrieval. Duplicate beacon/probe responses are updated if
+ * possible
+ */
+ wlan_ret_802_11_scan_store_beacon(pmpriv,
+ bss_idx,
+ num_in_table, bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL) {
+ PRINTM(MCMND, "No space for beacon, drop this entry\n");
+ num_in_table--;
+ continue;
+ }
+ /*
+ * If the TSF TLV was appended to the scan results, save
+ * this entry's TSF value in the networkTSF field. The
+ * networkTSF is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (ptsf_tlv) {
+ memcpy(pmpriv->adapter, &tsf_val,
+ &ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy(pmpriv->adapter, &bss_new_entry->network_tsf,
+ &tsf_val, sizeof(bss_new_entry->network_tsf));
+ }
+ band = BAND_G;
+ if (pchan_band_tlv) {
+ pchan_band = &pchan_band_tlv->chan_band_param[idx];
+ band =
+ radio_type_to_band(pchan_band->
+ radio_type & (MBIT(0) | MBIT(1)));
+ }
+
+ /* Save the band designation for this entry for use in join */
+ bss_new_entry->bss_band = band;
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) bss_new_entry->
+ bss_band,
+ (t_u16) bss_new_entry->
+ channel);
+
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
+ bss_new_entry, sizeof(pmadapter->pscan_table[bss_idx]));
+
+ } else {
+
+ /* Error parsing/interpreting the scan response, skipped */
+ PRINTM(MERROR,
+ "SCAN_RESP: wlan_interpret_bss_desc_with_ie returned error\n");
+ }
+ }
+
+ PRINTM(MINFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ pscan_rsp->number_of_sets,
+ num_in_table - pmadapter->num_in_scan_table, num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+ /* Update the age_in_second */
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->age_in_secs,
+ &age_ts_usec);
+ if (is_bgscan_resp)
+ goto done;
+ if (!util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)) {
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_buf,
+ MLAN_STATUS_SUCCESS);
+ }
+ pmadapter->bgscan_reported = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ } else {
+ /* If firmware not ready, do not issue any more scan commands */
+ if (pmadapter->hw_status != WlanHardwareStatusReady) {
+ /* Flush all pending scan commands */
+ wlan_flush_scan_queue(pmadapter);
+ /* Indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+ } else {
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+
+ done:
+ if (bss_new_entry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) bss_new_entry);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare an extended scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN_EXT command
+ * struct to send to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_802_11_SCAN_EXT structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_scan_ext(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &pcmd->params.ext_scan;
+ wlan_scan_cmd_config *pscan_cfg = MNULL;
+
+ ENTER();
+
+ pscan_cfg = (wlan_scan_cmd_config *) pdata_buf;
+
+ memcpy(pmpriv->adapter, pext_scan_cmd->tlv_buffer,
+ pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = wlan_cpu_to_le16((t_u16) (sizeof(pext_scan_cmd->reserved)
+ + pscan_cfg->tlv_buf_len
+ + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of extended scan
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_scan_ext(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ ENTER();
+
+ PRINTM(MINFO, "EXT scan returns successfully\n");
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function parse and store the extended scan results
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param number_of_sets Number of BSS
+ * @param pscan_resp A pointer to scan response buffer
+ * @param scan_resp_size Size of scan response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_parse_ext_scan_result(IN mlan_private * pmpriv,
+ IN t_u8 number_of_sets,
+ IN t_u8 * pscan_resp, IN t_u16 scan_resp_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ t_u8 *pbss_info;
+ t_u32 bytes_left;
+ t_u32 bytes_left_for_tlv;
+ t_u32 num_in_table;
+ t_u32 bss_idx;
+ t_u32 idx;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ t_u16 tlv_type, tlv_len;
+ MrvlIEtypes_Data_t *ptlv = MNULL;
+ MrvlIEtypes_Bss_Scan_Rsp_t *pscan_rsp_tlv = MNULL;
+ MrvlIEtypes_Bss_Scan_Info_t *pscan_info_tlv = MNULL;
+ t_u8 band;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ if (number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR, "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
+ number_of_sets);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = scan_resp_size;
+ PRINTM(MINFO, "EXT_SCAN: bss_descript_size %d\n", scan_resp_size);
+ PRINTM(MINFO, "EXT_SCAN: returned %d APs before parsing\n", number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ ptlv = (MrvlIEtypes_Data_t *) pscan_resp;
+
+ /*
+ * Process each scan response returned number_of_sets. Save
+ * the information in the bss_new_entry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF, (t_u8 **) & bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0; idx < number_of_sets && bytes_left >
+ sizeof(MrvlIEtypesHeader_t); idx++) {
+ tlv_type = wlan_le16_to_cpu(ptlv->header.type);
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+ if (bytes_left < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
+ PRINTM(MERROR, "EXT_SCAN: Error bytes left < TLV length\n");
+ break;
+ }
+ pscan_rsp_tlv = MNULL;
+ pscan_info_tlv = MNULL;
+ bytes_left_for_tlv = bytes_left;
+ /* BSS response TLV with beacon or probe response buffer at the initial
+ position of each descriptor */
+ if (tlv_type == TLV_TYPE_BSS_SCAN_RSP) {
+ pbss_info = (t_u8 *) ptlv;
+ pscan_rsp_tlv = (MrvlIEtypes_Bss_Scan_Rsp_t *) ptlv;
+ ptlv = (MrvlIEtypes_Data_t *) (ptlv->data + tlv_len);
+ bytes_left_for_tlv -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ } else
+ break;
+
+ /* Process variable TLV */
+ while (bytes_left_for_tlv >= sizeof(MrvlIEtypesHeader_t) &&
+ wlan_le16_to_cpu(ptlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) {
+ tlv_type = wlan_le16_to_cpu(ptlv->header.type);
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+ if (bytes_left_for_tlv < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
+ PRINTM(MERROR, "EXT_SCAN: Error in processing TLV, "
+ "bytes left < TLV length\n");
+ pscan_rsp_tlv = MNULL;
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_BSS_SCAN_INFO:
+ pscan_info_tlv = (MrvlIEtypes_Bss_Scan_Info_t *) ptlv;
+ if (tlv_len != sizeof(MrvlIEtypes_Bss_Scan_Info_t) -
+ sizeof(MrvlIEtypesHeader_t)) {
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ ptlv = (MrvlIEtypes_Data_t *) (ptlv->data + tlv_len);
+ bytes_left -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ bytes_left_for_tlv -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ }
+ /* No BSS response TLV */
+ if (pscan_rsp_tlv == MNULL)
+ break;
+
+ /* Advance pointer to the beacon buffer length and update the bytes
+ count so that the function wlan_interpret_bss_desc_with_ie() can
+ handle the scan buffer withut any change */
+ pbss_info += sizeof(t_u16);
+ bytes_left -= sizeof(t_u16);
+
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if (wlan_interpret_bss_desc_with_ie(pmadapter,
+ bss_new_entry,
+ &pbss_info,
+ &bytes_left) ==
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "EXT_SCAN: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss_new_entry->mac_address[0], bss_new_entry->mac_address[1],
+ bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
+ bss_new_entry->mac_address[4],
+ bss_new_entry->mac_address[5]);
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(pmadapter, bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bss_idx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len)
+ && (!memcmp(pmadapter, bss_new_entry->ssid.ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ PRINTM(MINFO, "EXT_SCAN: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to the last entry */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST) {
+ bss_idx--;
+ } else {
+ num_in_table++;
+ }
+ }
+
+ band = BAND_G;
+ /*
+ * If the BSS info TLV was appended to the scan results, save
+ * this entry's TSF value in the networkTSF field. The
+ * networkTSF is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (pscan_info_tlv) {
+ /* RSSI is 2 byte long */
+ bss_new_entry->rssi =
+ -(t_s32) (wlan_le16_to_cpu(pscan_info_tlv->rssi));
+ PRINTM(MINFO, "EXT_SCAN: RSSI=%d\n", bss_new_entry->rssi);
+ memcpy(pmpriv->adapter, &tsf_val, &pscan_info_tlv->tsf,
+ sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy(pmpriv->adapter, &bss_new_entry->network_tsf,
+ &tsf_val, sizeof(bss_new_entry->network_tsf));
+ band = radio_type_to_band(pscan_info_tlv->band);
+ }
+ /*
+ * Save the beacon/probe response returned for later application
+ * retrieval. Duplicate beacon/probe responses are updated if
+ * possible
+ */
+ wlan_ret_802_11_scan_store_beacon(pmpriv,
+ bss_idx,
+ num_in_table, bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL) {
+ PRINTM(MCMND, "No space for beacon, drop this entry\n");
+ num_in_table--;
+ continue;
+ }
+ /* Save the band designation for this entry for use in join */
+ bss_new_entry->bss_band = band;
+ cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) bss_new_entry->
+ bss_band,
+ (t_u16) bss_new_entry->
+ channel);
+
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
+ bss_new_entry, sizeof(pmadapter->pscan_table[bss_idx]));
+ } else {
+ /* Error parsing/interpreting the scan response, skipped */
+ PRINTM(MERROR,
+ "EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
+ }
+ }
+
+ PRINTM(MINFO, "EXT_SCAN: Scanned %2d APs, %d valid, %d total\n",
+ number_of_sets, num_in_table - pmadapter->num_in_scan_table,
+ num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+ /* Update the age_in_second */
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->age_in_secs,
+ &age_ts_usec);
+
+ done:
+ if (bss_new_entry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) bss_new_entry);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the event extended scan report
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_handle_event_ext_scan_report(IN mlan_private * pmpriv,
+ IN mlan_buffer * pmbuf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ mlan_event_scan_result *pevent_scan = (pmlan_event_scan_result)
+ (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 *ptlv = (pmbuf->pbuf + pmbuf->data_offset
+ + sizeof(mlan_event_scan_result));
+ t_u16 tlv_buf_left = wlan_cpu_to_le16(pevent_scan->buf_size);
+
+ DBG_HEXDUMP(MCMD_D, "EVENT EXT_SCAN", pmbuf->pbuf +
+ pmbuf->data_offset, pmbuf->data_len);
+ wlan_parse_ext_scan_result(pmpriv, pevent_scan->num_of_set,
+ ptlv, tlv_buf_left);
+ if (!pevent_scan->more_event) {
+ pioctl_req = pmadapter->pext_scan_ioctl_req;
+ if (!util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)) {
+ pmadapter->pext_scan_ioctl_req = MNULL;
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ pmadapter->bgscan_reported = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ } else {
+ /* If firmware not ready, do not issue any more scan commands */
+ if (pmadapter->hw_status != WlanHardwareStatusReady) {
+ /* Flush all pending scan commands */
+ wlan_flush_scan_queue(pmadapter);
+ /* Indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_req,
+ MLAN_STATUS_FAILURE);
+ }
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ cmd_pending_q */
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->
+ scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_query.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_BG_SCAN_QUERY *bg_query = &pcmd->params.bg_scan_query;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) + S_DS_GEN);
+
+ bg_query->flush = MTRUE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbg_scan_in pointer to scan configuration parameters
+ * @param tlv_chan_list A pointer to structure MrvlIEtypes_ChanListParamSet_t
+ *
+ * @return channel number
+ */
+static t_u8
+wlan_bgscan_create_channel_list(IN mlan_private * pmpriv,
+ IN const wlan_bgscan_cfg * pbg_scan_in,
+ MrvlIEtypes_ChanListParamSet_t * tlv_chan_list)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx = 0;
+ t_u32 next_chan;
+ t_u8 scan_type;
+ t_u8 radio_type;
+
+ ENTER();
+
+ for (region_idx = 0;
+ region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
+
+ if (wlan_11d_is_enabled(pmpriv) && pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ if (pbg_scan_in && !pbg_scan_in->chan_list[0].chan_number &&
+ pbg_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
+ radio_type = pbg_scan_in->chan_list[0].radio_type & ~BAND_SPECIFIED;
+ if (!radio_type && (pscan_region->band != BAND_B) &&
+ (pscan_region->band != BAND_G))
+ continue;
+ if (radio_type && (pscan_region->band != BAND_A))
+ continue;
+ }
+ if (!wlan_is_band_compatible
+ (pmpriv->config_bands | pmadapter->adhoc_start_band,
+ pscan_region->band))
+ continue;
+ for (next_chan = 0;
+ next_chan < pscan_region->num_cfp; next_chan++, chan_idx++) {
+ if (chan_idx >= WLAN_BG_SCAN_CHAN_MAX)
+ break;
+ /* Set the default scan type to ACTIVE SCAN type, will later be
+ changed to passive on a per channel basis if restricted by
+ regulatory requirements (11d or 11h) */
+ scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ cfp = pscan_region->pcfp + next_chan;
+ if (scan_type == MLAN_SCAN_TYPE_ACTIVE
+ && wlan_11d_is_enabled(pmpriv)) {
+ scan_type = wlan_11d_get_scan_type(pmadapter,
+ pscan_region->band,
+ (t_u8) cfp->channel,
+ &pmadapter->
+ parsed_region_chan);
+ }
+ switch (pscan_region->band) {
+ case BAND_A:
+ tlv_chan_list->chan_scan_param[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_A;
+ if (!wlan_11d_is_enabled(pmpriv)) {
+ /* 11D not available... play it safe on DFS channels */
+ if (wlan_11h_radar_detect_required
+ (pmpriv, (t_u8) cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ if (wlan_bg_scan_type_is_passive(pmpriv, (t_u8) cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ default:
+ tlv_chan_list->chan_scan_param[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ if (pbg_scan_in && pbg_scan_in->chan_list[0].scan_time) {
+ tlv_chan_list->chan_scan_param[chan_idx].max_scan_time =
+ wlan_cpu_to_le16((t_u16) pbg_scan_in->chan_list[0].
+ scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx].min_scan_time =
+ wlan_cpu_to_le16((t_u16) pbg_scan_in->chan_list[0].
+ scan_time);
+ } else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx].min_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ } else {
+ tlv_chan_list->chan_scan_param[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx].min_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ }
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
+ passive_scan = MTRUE;
+ } else {
+ tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
+ passive_scan = MFALSE;
+ }
+
+ tlv_chan_list->chan_scan_param[chan_idx].chan_number =
+ (t_u8) cfp->channel;
+ tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
+ disable_chan_filt = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return chan_idx;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan = &pcmd->params.bg_scan_config;
+ wlan_bgscan_cfg *bg_scan_in = (wlan_bgscan_cfg *) pdata_buf;
+ t_u16 cmd_size = 0;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv = MNULL;
+ MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_tlv = MNULL;
+ MrvlIEtypes_BeaconLowSnrThreshold_t *snr_tlv = MNULL;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ MrvlIEtypes_StartLater_t *tlv_start_later = MNULL;
+ MrvlIEtypes_RepeatCount_t *tlv_repeat = MNULL;
+ t_u8 *tlv = MNULL;
+ t_u16 num_probes = 0;
+ t_u32 ssid_idx;
+ t_u32 ssid_len = 0;
+ t_u32 chan_idx;
+ t_u32 chan_num;
+ t_u8 radio_type;
+ t_u16 scan_dur;
+ t_u8 scan_type;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+ bg_scan->action = wlan_cpu_to_le16(bg_scan_in->action);
+ bg_scan->enable = bg_scan_in->enable;
+ bg_scan->bss_type = bg_scan_in->bss_type;
+ cmd_size = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG) + S_DS_GEN;
+ if (bg_scan_in->chan_per_scan)
+ bg_scan->chan_per_scan = bg_scan_in->chan_per_scan;
+ else
+ bg_scan->chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ if (bg_scan_in->scan_interval)
+ bg_scan->scan_interval = wlan_cpu_to_le32(bg_scan_in->scan_interval);
+ else
+ bg_scan->scan_interval = wlan_cpu_to_le32(DEFAULT_BGSCAN_INTERVAL);
+ bg_scan->report_condition = wlan_cpu_to_le32(bg_scan_in->report_condition);
+
+ if ((bg_scan_in->action == BG_SCAN_ACT_GET) ||
+ (bg_scan_in->action == BG_SCAN_ACT_GET_PPS_UAPSD) || (!bg_scan->enable))
+ goto done;
+
+ tlv = (t_u8 *) bg_scan + sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
+ num_probes = (bg_scan_in->num_probes ? bg_scan_in->num_probes :
+ pmadapter->scan_probes);
+ if (num_probes) {
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *) tlv;
+ pnum_probes_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(pnum_probes_tlv->num_probes));
+ pnum_probes_tlv->num_probes = wlan_cpu_to_le16((t_u16) num_probes);
+ tlv += sizeof(MrvlIEtypes_NumProbes_t);
+ cmd_size += sizeof(MrvlIEtypes_NumProbes_t);
+ }
+ if (bg_scan_in->rssi_threshold) {
+ rssi_tlv = (MrvlIEtypes_BeaconLowRssiThreshold_t *) tlv;
+ rssi_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
+ rssi_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_tlv->value = bg_scan_in->rssi_threshold;
+ rssi_tlv->frequency = 0;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (bg_scan_in->snr_threshold) {
+ snr_tlv = (MrvlIEtypes_BeaconLowSnrThreshold_t *) tlv;
+ snr_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_tlv->value = bg_scan_in->snr_threshold;
+ snr_tlv->frequency = 0;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (bg_scan_in->repeat_count) {
+ tlv_repeat = (MrvlIEtypes_RepeatCount_t *) tlv;
+ tlv_repeat->header.type = wlan_cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
+ tlv_repeat->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_RepeatCount_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_repeat->repeat_count = wlan_cpu_to_le16(bg_scan_in->repeat_count);
+ tlv += sizeof(MrvlIEtypes_RepeatCount_t);
+ cmd_size += sizeof(MrvlIEtypes_RepeatCount_t);
+ }
+ for (ssid_idx = 0; ((ssid_idx < NELEMENTS(bg_scan_in->ssid_list))
+ && (*bg_scan_in->ssid_list[ssid_idx].ssid ||
+ bg_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+ ssid_len = wlan_strlen((t_s8 *) bg_scan_in->ssid_list[ssid_idx].ssid);
+ pwildcard_ssid_tlv = (MrvlIEtypes_WildCardSsIdParamSet_t *) tlv;
+ pwildcard_ssid_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len =
+ (t_u16) (ssid_len + sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length =
+ bg_scan_in->ssid_list[ssid_idx].max_len;
+ memcpy(pmadapter, pwildcard_ssid_tlv->ssid,
+ bg_scan_in->ssid_list[ssid_idx].ssid, MIN(MLAN_MAX_SSID_LENGTH,
+ ssid_len));
+ tlv +=
+ sizeof(pwildcard_ssid_tlv->header) + pwildcard_ssid_tlv->header.len;
+ cmd_size +=
+ sizeof(pwildcard_ssid_tlv->header) + pwildcard_ssid_tlv->header.len;
+ pwildcard_ssid_tlv->header.len =
+ wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
+ pwildcard_ssid_tlv->ssid, pwildcard_ssid_tlv->max_ssid_length);
+ }
+ if (bg_scan_in->chan_list[0].chan_number) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+ chan_num = 0;
+ for (chan_idx = 0; chan_idx < WLAN_BG_SCAN_CHAN_MAX
+ && bg_scan_in->chan_list[chan_idx].chan_number; chan_idx++) {
+ radio_type = bg_scan_in->chan_list[chan_idx].radio_type;
+ if (!wlan_is_band_compatible
+ (pmpriv->config_bands | pmadapter->adhoc_start_band,
+ radio_type_to_band(radio_type)))
+ continue;
+ scan_type = bg_scan_in->chan_list[chan_idx].scan_type;
+ /* Prevent active scanning on a radar controlled channel */
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (wlan_11h_radar_detect_required
+ (pmpriv, bg_scan_in->chan_list[chan_idx].chan_number)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_BG) {
+ if (wlan_bg_scan_type_is_passive
+ (pmpriv, bg_scan_in->chan_list[chan_idx].chan_number)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ tlv_chan_list->chan_scan_param[chan_num].chan_number =
+ bg_scan_in->chan_list[chan_idx].chan_number;
+ tlv_chan_list->chan_scan_param[chan_num].radio_type =
+ bg_scan_in->chan_list[chan_idx].radio_type;
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_num].chan_scan_mode.
+ passive_scan = MTRUE;
+ } else {
+ tlv_chan_list->chan_scan_param[chan_num].chan_scan_mode.
+ passive_scan = MFALSE;
+ }
+ if (bg_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (t_u16) bg_scan_in->chan_list[chan_idx].scan_time;
+ } else {
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else {
+ scan_dur = pmadapter->specific_scan_time;
+ }
+ }
+ tlv_chan_list->chan_scan_param[chan_num].min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ tlv_chan_list->chan_scan_param[chan_num].max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ chan_num++;
+ }
+ tlv_chan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ } else {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ chan_num =
+ wlan_bgscan_create_channel_list(pmpriv, bg_scan_in, tlv_chan_list);
+ tlv_chan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ }
+ tlv_start_later = (MrvlIEtypes_StartLater_t *) tlv;
+ tlv_start_later->header.type = wlan_cpu_to_le16(TLV_TYPE_STARTBGSCANLATER);
+ tlv_start_later->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_StartLater_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_start_later->value = 0;
+ tlv += sizeof(MrvlIEtypes_StartLater_t);
+ cmd_size += sizeof(MrvlIEtypes_StartLater_t);
+ done:
+ pcmd->size = wlan_cpu_to_le16(cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of extended scan
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_scan *pscan = MNULL;
+ HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan = &resp->params.bg_scan_config;
+ wlan_bgscan_cfg *bg_scan_out = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ pscan = (mlan_ds_scan *) pioctl_buf->pbuf;
+ bg_scan_out = (wlan_bgscan_cfg *) pscan->param.user_scan.scan_cfg_buf;
+ bg_scan_out->action = wlan_le16_to_cpu(bg_scan->action);
+ if ((bg_scan_out->action == BG_SCAN_ACT_GET) &&
+ (bg_scan_out->action == BG_SCAN_ACT_GET_PPS_UAPSD)) {
+ bg_scan_out->enable = bg_scan->enable;
+ bg_scan_out->bss_type = bg_scan->bss_type;
+ bg_scan_out->chan_per_scan = bg_scan->chan_per_scan;
+ bg_scan_out->scan_interval =
+ wlan_le32_to_cpu(bg_scan->scan_interval);
+ bg_scan_out->report_condition =
+ wlan_le32_to_cpu(bg_scan->report_condition);
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_scan) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of bgscan_query
+ * @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 or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_bgscan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_scan *pscan = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+ wlan_ret_802_11_scan(pmpriv, resp, MNULL);
+ if (pioctl_buf) {
+ pscan = (mlan_ds_scan *) pioctl_buf->pbuf;
+ pscan->param.scan_resp.pscan_table = (t_u8 *) pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table = pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
+ pioctl_buf->data_read_written = sizeof(mlan_scan_resp) +
+ MLAN_SUB_COMMAND_SIZE;
+
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds ssid in ssid list.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32
+wlan_find_ssid_in_list(IN mlan_private * pmpriv,
+ IN mlan_802_11_ssid * ssid,
+ IN t_u8 * bssid, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1, j;
+ t_u8 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+ PRINTM(MINFO, "Num of entries in scan table = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Loop through the table until the maximum is reached or until a match
+ * is found based on the bssid field comparison
+ */
+ for (i = 0;
+ i < pmadapter->num_in_scan_table && (!bssid || (bssid && net < 0));
+ i++) {
+ if (!wlan_ssid_cmp(pmadapter, &pmadapter->pscan_table[i].ssid, ssid) &&
+ (!bssid
+ || !memcmp(pmadapter, pmadapter->pscan_table[i].mac_address, bssid,
+ MLAN_MAC_ADDR_LENGTH))) {
+
+ if (((mode == MLAN_BSS_MODE_INFRA) &&
+ !wlan_is_band_compatible(pmpriv->config_bands,
+ pmadapter->pscan_table[i].bss_band))
+ ||
+ (wlan_find_cfp_by_band_and_channel
+ (pmadapter, (t_u8) pmadapter->pscan_table[i].bss_band,
+ (t_u16) pmadapter->pscan_table[i].channel) == MNULL)) {
+ continue;
+ }
+
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ j = wlan_is_network_compatible(pmpriv, i, mode);
+
+ if (j >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ } else {
+ if (net == -1) {
+ net = j;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ /*
+ * Do not check compatibility if the mode requested is
+ * Auto/Unknown. Allows generic find to work without
+ * verifying against the Adapter security settings
+ */
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32
+wlan_find_bssid_in_list(IN mlan_private * pmpriv,
+ IN t_u8 * bssid, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1;
+ t_u32 i;
+
+ ENTER();
+
+ if (!bssid) {
+ LEAVE();
+ return -1;
+ }
+
+ PRINTM(MINFO, "FindBSSID: Num of BSSIDs = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. The loop will continue
+ * past a matched bssid that is not compatible in case there is an
+ * AP with multiple SSIDs assigned to the same BSSID
+ */
+ for (i = 0; net < 0 && i < pmadapter->num_in_scan_table; i++) {
+ if (!memcmp
+ (pmadapter, pmadapter->pscan_table[i].mac_address, bssid,
+ MLAN_MAC_ADDR_LENGTH)) {
+ if (((mode == MLAN_BSS_MODE_INFRA) &&
+ !wlan_is_band_compatible(pmpriv->config_bands,
+ pmadapter->pscan_table[i].bss_band))
+ ||
+ (wlan_find_cfp_by_band_and_channel
+ (pmadapter, (t_u8) pmadapter->pscan_table[i].bss_band,
+ (t_u16) pmadapter->pscan_table[i].channel) == MNULL)) {
+ continue;
+ }
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ net = wlan_is_network_compatible(pmpriv, i, mode);
+ break;
+ default:
+ net = i;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+t_s32
+wlan_ssid_cmp(IN pmlan_adapter pmadapter,
+ IN mlan_802_11_ssid * ssid1, IN mlan_802_11_ssid * ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(pmadapter, ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief This function inserts scan command node to scan_pending_q.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @return N/A
+ */
+t_void
+wlan_queue_scan_cmd(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param preq_ssid_bssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status
+wlan_find_best_network(IN mlan_private * pmpriv,
+ OUT mlan_ssid_bssid * preq_ssid_bssid)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ BSSDescriptor_t *preq_bss;
+ t_s32 i;
+
+ ENTER();
+
+ memset(pmadapter, preq_ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ i = wlan_find_best_network_in_list(pmpriv);
+
+ if (i >= 0) {
+ preq_bss = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &preq_ssid_bssid->ssid, &preq_bss->ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(pmadapter, (t_u8 *) & preq_ssid_bssid->bssid,
+ (t_u8 *) & preq_bss->mac_address, MLAN_MAC_ADDR_LENGTH);
+
+ /* Make sure we are in the right mode */
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_AUTO)
+ pmpriv->bss_mode = preq_bss->bss_mode;
+ }
+
+ if (!preq_ssid_bssid->ssid.ssid_len) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "Best network found = [%s], "
+ "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ preq_ssid_bssid->ssid.ssid,
+ preq_ssid_bssid->bssid[0], preq_ssid_bssid->bssid[1],
+ preq_ssid_bssid->bssid[2], preq_ssid_bssid->bssid[3],
+ preq_ssid_bssid->bssid[4], preq_ssid_bssid->bssid[5]);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param preq_ssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status
+wlan_scan_specific_ssid(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN mlan_802_11_ssid * preq_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_user_scan_cfg *pscan_cfg;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ if (!preq_ssid) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_scan_delete_ssid_table_entry(pmpriv, preq_ssid);
+
+ ret =
+ pcb->moal_malloc(pmpriv->adapter->pmoal_handle,
+ sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
+ (t_u8 **) & pscan_cfg);
+
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, pscan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
+
+ memcpy(pmpriv->adapter, pscan_cfg->ssid_list[0].ssid,
+ preq_ssid->ssid, preq_ssid->ssid_len);
+ pscan_cfg->keep_previous_scan = MTRUE;
+
+ ret = wlan_scan_networks(pmpriv, pioctl_buf, pscan_cfg);
+
+ if (pscan_cfg)
+ pcb->moal_mfree(pmpriv->adapter->pmoal_handle, (t_u8 *) pscan_cfg);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Save a beacon buffer of the current bss descriptor
+ * Save the current beacon buffer to restore in the following cases that
+ * makes the bcn_buf not to contain the current ssid's beacon buffer.
+ * - the current ssid was not found somehow in the last scan.
+ * - the current ssid was the last entry of the scan table and overloaded.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_save_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* save the beacon buffer if it is not saved or updated */
+ if ((pmpriv->pcurr_bcn_buf == MNULL) ||
+ (pmpriv->curr_bcn_size != pcurr_bss->beacon_buf_size) ||
+ (memcmp(pmpriv->adapter, pmpriv->pcurr_bcn_buf, pcurr_bss->pbeacon_buf,
+ pcurr_bss->beacon_buf_size))) {
+
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+ pmpriv->curr_bcn_size = pcurr_bss->beacon_buf_size;
+
+ if (pmpriv->curr_bcn_size) {
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ pcurr_bss->beacon_buf_size, MLAN_MEM_DEF,
+ &pmpriv->pcurr_bcn_buf);
+
+ if ((ret == MLAN_STATUS_SUCCESS) && pmpriv->pcurr_bcn_buf) {
+ memcpy(pmpriv->adapter, pmpriv->pcurr_bcn_buf,
+ pcurr_bss->pbeacon_buf, pcurr_bss->beacon_buf_size);
+ PRINTM(MINFO, "current beacon saved %d\n",
+ pmpriv->curr_bcn_size);
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Free a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ ENTER();
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sdio.c b/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
new file mode 100644
index 000000000000..02e73477b619
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
@@ -0,0 +1,1661 @@
+/** @file mlan_sdio.c
+ *
+ * @brief This file contains SDIO specific code
+ *
+ * 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/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function initialize the SDIO port
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_init_ioport(mlan_adapter * pmadapter)
+{
+ t_u32 reg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ pmadapter->ioport = 0;
+
+ /* Read the IO port */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_0_REG, &reg))
+ pmadapter->ioport |= (reg & 0xff);
+ else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_1_REG, &reg))
+ pmadapter->ioport |= ((reg & 0xff) << 8);
+ else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_2_REG, &reg))
+ pmadapter->ioport |= ((reg & 0xff) << 16);
+ else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "SDIO FUNC1 IO port: 0x%x\n", pmadapter->ioport);
+
+ /* Set Host interrupt reset to read to clear */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_RSR_REG, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_RSR_REG,
+ reg | HOST_INT_RSR_MASK);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Dnld/Upld ready set to auto reset */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_MISC_CFG_REG, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, CARD_MISC_CFG_REG,
+ reg | AUTO_RE_ENABLE_INT);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
+ * @param port Port
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_write_data_sync(mlan_adapter * pmadapter, mlan_buffer * pmbuf, t_u32 port)
+{
+ t_u32 i = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ do {
+ ret =
+ pcb->moal_write_data_sync(pmadapter->pmoal_handle, pmbuf, port, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ i++;
+ PRINTM(MERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+ ret);
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, 0x04)) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ goto exit;
+ }
+ }
+ } while (ret == MLAN_STATUS_FAILURE);
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets available SDIO port for reading cmd/data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_rd_port(mlan_adapter * pmadapter, t_u8 * pport)
+{
+ t_u32 rd_bitmap = pmadapter->mp_rd_bitmap;
+
+ ENTER();
+
+ PRINTM(MIF_D, "wlan_get_rd_port: mp_rd_bitmap=0x%08x\n", rd_bitmap);
+
+ if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (pmadapter->mp_rd_bitmap & CTRL_PORT_MASK) {
+ pmadapter->mp_rd_bitmap &= (t_u32) (~CTRL_PORT_MASK);
+ *pport = CTRL_PORT;
+ PRINTM(MIF_D, "wlan_get_rd_port: port=%d mp_rd_bitmap=0x%08x\n", *pport,
+ pmadapter->mp_rd_bitmap);
+ } else {
+ if (pmadapter->mp_rd_bitmap & (1 << pmadapter->curr_rd_port)) {
+ pmadapter->mp_rd_bitmap &=
+ (t_u32) (~(1 << pmadapter->curr_rd_port));
+ *pport = pmadapter->curr_rd_port;
+
+ /* hw rx wraps round only after port (MAX_PORT-1) */
+ if (++pmadapter->curr_rd_port == MAX_PORT)
+ /* port 0 is reserved for cmd port */
+ pmadapter->curr_rd_port = 1;
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MIF_D, "port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
+ *pport, rd_bitmap, pmadapter->mp_rd_bitmap);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function gets available SDIO port for writing data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_wr_port_data(mlan_adapter * pmadapter, t_u8 * pport)
+{
+ t_u32 wr_bitmap = pmadapter->mp_wr_bitmap;
+
+ ENTER();
+
+ PRINTM(MIF_D, "wlan_get_wr_port_data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
+
+ if (!(wr_bitmap & pmadapter->mp_data_port_mask)) {
+ pmadapter->data_sent = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)) {
+ pmadapter->mp_wr_bitmap &= (t_u32) (~(1 << pmadapter->curr_wr_port));
+ *pport = pmadapter->curr_wr_port;
+ if (++pmadapter->curr_wr_port == pmadapter->mp_end_port)
+ pmadapter->curr_wr_port = 1;
+ } else {
+ pmadapter->data_sent = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if (*pport == CTRL_PORT) {
+ PRINTM(MERROR,
+ "Invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *pport, pmadapter->curr_wr_port, wr_bitmap,
+ pmadapter->mp_wr_bitmap);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MIF_D, "port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *pport, wr_bitmap, pmadapter->mp_wr_bitmap);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function polls the card status register.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param bits the bit mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_poll_card_status(mlan_adapter * pmadapter, t_u8 bits)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 tries;
+ t_u32 cs = 0;
+
+ ENTER();
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if (pcb->
+ moal_read_reg(pmadapter->pmoal_handle, CARD_TO_HOST_EVENT_REG,
+ &cs) != MLAN_STATUS_SUCCESS)
+ break;
+ else if ((cs & bits) == bits) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ wlan_udelay(pmadapter, 10);
+ }
+
+ PRINTM(MERROR, "wlan_sdio_poll_card_status failed, tries = %d, cs = 0x%x\n",
+ tries, cs);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function reads firmware status registers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param dat A pointer to keep returned data
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_read_fw_status(mlan_adapter * pmadapter, t_u16 * dat)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 fws0 = 0, fws1 = 0;
+
+ ENTER();
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS0_REG,
+ &fws0)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS1_REG,
+ &fws1)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *dat = (t_u16) ((fws1 << 8) | fws0);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** @brief This function disables the host interrupts mask.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
+{
+ t_u32 host_int_mask = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Read back the host_int_mask register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG,
+ &host_int_mask)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Update with the mask and write back to the register */
+ host_int_mask &= ~mask;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG,
+ host_int_mask)) {
+ PRINTM(MWARN, "Disable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupts mask
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Simply write the mask to the register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG, mask)) {
+ PRINTM(MWARN, "Enable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads data from the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type A pointer to keep type as data or command
+ * @param nb A pointer to keep the data/cmd length returned in buffer
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param npayload the length of data/cmd buffer
+ * @param ioport the SDIO ioport
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_card_to_host(mlan_adapter * pmadapter,
+ t_u32 * type, t_u32 * nb, pmlan_buffer pmbuf,
+ t_u32 npayload, t_u32 ioport)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmbuf) {
+ PRINTM(MWARN, "pmbuf is NULL!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, pmbuf, ioport, 0);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "card_to_host, read iomem failed: %d\n", ret);
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ *nb = wlan_le16_to_cpu(*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset));
+ if (*nb > npayload) {
+ PRINTM(MERROR, "invalid packet, *nb=%d, npayload=%d\n", *nb, npayload);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Rd", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(*nb, MAX_DATA_DUMP_LEN));
+
+ *type = wlan_le16_to_cpu(*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset + 2));
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads FW blocks to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_prog_fw_w_helper(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *firmware = pmfw->pfw_buf;
+ t_u32 firmwarelen = pmfw->fw_len;
+ t_u32 offset = 0;
+ t_u32 base0, base1;
+ t_void *tmpfwbuf = MNULL;
+ t_u32 tmpfwbufsz;
+ t_u8 *fwbuf;
+ mlan_buffer mbuf;
+ t_u16 len = 0;
+ t_u32 txlen = 0, tx_blocks = 0, tries = 0;
+ t_u32 i = 0;
+
+ ENTER();
+
+ if (!firmware && !pcb->moal_get_fw_data) {
+ PRINTM(MMSG, "No firmware image found! Terminating download\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "WLAN: Downloading FW image (%d bytes)\n", firmwarelen);
+
+ tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, DMA_ALIGNMENT);
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, tmpfwbufsz,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & tmpfwbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) {
+ PRINTM(MERROR,
+ "Unable to allocate buffer for firmware. Terminating download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmadapter, tmpfwbuf, 0, tmpfwbufsz);
+ /* Ensure 8-byte aligned firmware buffer */
+ fwbuf = (t_u8 *) ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);
+
+ /* Perform firmware data transfer */
+ do {
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+ ret =
+ wlan_sdio_poll_card_status(pmadapter,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL,
+ "WLAN: FW download with helper poll status timeout @ %d\n",
+ offset);
+ goto done;
+ }
+
+ /* More data? */
+ if (firmwarelen && offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if ((ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ READ_BASE_0_REG,
+ &base0)) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev BASE0 register read failed:"
+ " base0=0x%04X(%d). Terminating download\n", base0,
+ base0);
+ goto done;
+ }
+ if ((ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ READ_BASE_1_REG,
+ &base1)) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev BASE1 register read failed:"
+ " base1=0x%04X(%d). Terminating download\n", base1,
+ base1);
+ goto done;
+ }
+ len = (t_u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
+
+ if (len)
+ break;
+ wlan_udelay(pmadapter, 10);
+ }
+
+ if (!len)
+ break;
+ else if (len > WLAN_UPLD_SIZE) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & MBIT(0)) {
+ i++;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, over max retry count\n",
+ offset);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MERROR, "WLAN: FW CRC error indicated by the helper:"
+ " len = 0x%04X, txlen = %d\n", len, txlen);
+ len &= ~MBIT(0);
+
+ PRINTM(MERROR, "WLAN: retry: %d, offset %d\n", i, offset);
+ DBG_HEXDUMP(MERROR, "WLAN: FW block:", mbuf.pbuf, len);
+
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ i = 0;
+
+ /* Set blocksize to transfer - checking for last block */
+ if (firmwarelen && firmwarelen - offset < txlen) {
+ txlen = firmwarelen - offset;
+ }
+ PRINTM(MINFO, ".");
+
+ tx_blocks =
+ (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD -
+ 1) / MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ if (firmware)
+ memmove(pmadapter, fwbuf, &firmware[offset], txlen);
+ else
+ pcb->moal_get_fw_data(pmadapter->pmoal_handle, offset, txlen,
+ fwbuf);
+ }
+
+ /* Send data */
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *) fwbuf;
+ mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ ret =
+ pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
+ pmadapter->ioport, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "WLAN: FW download, write iomem (%d) failed @ %d\n",
+ i, offset);
+ if (pcb->
+ moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG,
+ 0x04) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ offset += txlen;
+ } while (MTRUE);
+
+ PRINTM(MINFO, "\nFW download over, size %d bytes\n", offset);
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (tmpfwbuf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) tmpfwbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function disables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_disable_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_disable_host_int_mask(pmadapter, HIM_DISABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function decodes the rx packet &
+ * calls corresponding handlers according to the packet type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param upld_typ Type of rx packet
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_decode_rx_packet(mlan_adapter * pmadapter, mlan_buffer * pmbuf,
+ t_u32 upld_typ)
+{
+ t_u8 *cmdBuf;
+ t_u32 event;
+
+ ENTER();
+
+ switch (upld_typ) {
+ case MLAN_TYPE_DATA:
+ PRINTM(MINFO, "--- Rx: Data packet ---\n");
+ pmbuf->data_len = (pmadapter->upld_len - INTF_HEADER_LEN);
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ wlan_handle_rx_packet(pmadapter, pmbuf);
+ pmadapter->data_received = MTRUE;
+ break;
+
+ case MLAN_TYPE_CMD:
+ PRINTM(MINFO, "--- Rx: Cmd Response ---\n");
+ /* take care of curr_cmd = NULL case */
+ if (!pmadapter->curr_cmd) {
+ cmdBuf = pmadapter->upld_buf;
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
+ wlan_process_sleep_confirm_resp(pmadapter,
+ pmbuf->pbuf +
+ pmbuf->data_offset +
+ INTF_HEADER_LEN,
+ pmadapter->upld_len -
+ INTF_HEADER_LEN);
+ }
+ pmadapter->upld_len -= INTF_HEADER_LEN;
+ memcpy(pmadapter, cmdBuf,
+ pmbuf->pbuf + pmbuf->data_offset + INTF_HEADER_LEN,
+ MIN(MRVDRV_SIZE_OF_CMD_BUFFER,
+ pmadapter->upld_len - INTF_HEADER_LEN));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ pmadapter->cmd_resp_received = MTRUE;
+ pmadapter->upld_len -= INTF_HEADER_LEN;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ pmadapter->curr_cmd->respbuf = pmbuf;
+ }
+ break;
+
+ case MLAN_TYPE_EVENT:
+ PRINTM(MINFO, "--- Rx: Event ---\n");
+ event = *(t_u32 *) & pmbuf->pbuf[pmbuf->data_offset + INTF_HEADER_LEN];
+ pmadapter->event_cause = wlan_le32_to_cpu(event);
+ if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) &&
+ ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) < MAX_EVENT_SIZE)) {
+ memcpy(pmadapter, pmadapter->event_body,
+ pmbuf->pbuf + pmbuf->data_offset + MLAN_EVENT_HEADER_LEN,
+ pmadapter->upld_len - MLAN_EVENT_HEADER_LEN);
+ }
+
+ /* event cause has been saved to adapter->event_cause */
+ pmadapter->event_received = MTRUE;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmadapter->pmlan_buffer_event = pmbuf;
+
+ /* remove SDIO header */
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ pmbuf->data_len -= INTF_HEADER_LEN;
+ break;
+
+ default:
+ PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/**
+ * @brief This function receives data from the card in aggregate mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param port Current port on which packet needs to be rxed
+ * @param rx_len Length of received packet
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_card_to_host_mp_aggr(mlan_adapter * pmadapter, mlan_buffer
+ * pmbuf, t_u8 port, t_u16 rx_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 f_do_rx_aggr = 0;
+ t_s32 f_do_rx_cur = 0;
+ t_s32 f_aggr_cur = 0;
+ mlan_buffer mbuf_aggr;
+ mlan_buffer *mbuf_deaggr;
+ t_u32 pind = 0;
+ t_u32 pkt_len, pkt_type = 0;
+ t_u8 *curr_ptr;
+ t_u32 cmd53_port = 0;
+
+ ENTER();
+
+ if (port == CTRL_PORT) {
+ /* Read the command response or event without aggr */
+ PRINTM(MINFO, "card_2_host_mp_aggr: No aggr for control port\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (!pmadapter->mpa_rx.enabled) {
+ PRINTM(MINFO, "card_2_host_mp_aggr: rx aggregation disabled !\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (pmadapter->mp_rd_bitmap & (~((t_u32) CTRL_PORT_MASK))) {
+ /* Some more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_aggr = 1;
+ f_do_rx_cur = 1;
+ }
+ } else {
+ /* Rx aggr not in progress */
+ f_aggr_cur = 1;
+ }
+
+ } else {
+ /* No more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ f_do_rx_aggr = 1;
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_cur = 1;
+ }
+ } else {
+ f_do_rx_cur = 1;
+ }
+
+ }
+
+ if (f_aggr_cur) {
+ PRINTM(MINFO, "Current packet aggregation.\n");
+ /* Curr pkt can be aggregated */
+ MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
+
+ if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MINFO,
+ "card_2_host_mp_aggr: Aggregation Packet limit reached\n");
+ /* No more pkts allowed in Aggr buf, rx it */
+ f_do_rx_aggr = 1;
+ }
+ }
+
+ if (f_do_rx_aggr) {
+ /* do aggr RX now */
+ PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n",
+ pmadapter->mpa_rx.pkt_cnt);
+
+ memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_rx.buf;
+ mbuf_aggr.data_len = pmadapter->mpa_rx.buf_len;
+ cmd53_port = (pmadapter->ioport | SDIO_MPA_ADDR_BASE |
+ (pmadapter->mpa_rx.ports << 4)) +
+ pmadapter->mpa_rx.start_port;
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf_aggr,
+ cmd53_port, 0)) {
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO MP-A Blk Rd", pmadapter->mpa_rx.buf,
+ MIN(pmadapter->mpa_rx.buf_len, MAX_DATA_DUMP_LEN));
+
+ curr_ptr = pmadapter->mpa_rx.buf;
+
+ for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
+
+ /* get curr PKT len & type */
+ pkt_len = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[0]);
+ pkt_type = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[2]);
+
+ PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n", pind,
+ pkt_len, pkt_type);
+
+ /* copy pkt to deaggr buf */
+ mbuf_deaggr = pmadapter->mpa_rx.mbuf_arr[pind];
+ if ((pkt_type == MLAN_TYPE_DATA) &&
+ (pkt_len <= pmadapter->mpa_rx.len_arr[pind])) {
+ memcpy(pmadapter, mbuf_deaggr->pbuf + mbuf_deaggr->data_offset,
+ curr_ptr, pkt_len);
+ pmadapter->upld_len = pkt_len;
+ /* Process de-aggr packet */
+ wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type);
+ } else {
+ PRINTM(MERROR,
+ "Wrong aggr packet: type=%d, len=%d, max_len=%d\n",
+ pkt_type, pkt_len, pmadapter->mpa_rx.len_arr[pind]);
+ wlan_free_mlan_buffer(pmadapter, mbuf_deaggr);
+ }
+ curr_ptr += pmadapter->mpa_rx.len_arr[pind];
+ }
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ rx_curr_single:
+ if (f_do_rx_cur) {
+ PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port, rx_len);
+
+ if (MLAN_STATUS_SUCCESS != wlan_sdio_card_to_host(pmadapter, &pkt_type,
+ (t_u32 *) &
+ pmadapter->upld_len,
+ pmbuf, rx_len,
+ pmadapter->ioport +
+ port)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if ((port == CTRL_PORT) && ((pkt_type != MLAN_TYPE_EVENT) &&
+ (pkt_type != MLAN_TYPE_CMD))) {
+ PRINTM(MERROR, "Wrong pkt from CTRL PORT: type=%d, len=%dd\n",
+ pkt_type, pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type);
+ }
+
+ done:
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* MP-A transfer failed - cleanup */
+ for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
+ wlan_free_mlan_buffer(pmadapter,
+ pmadapter->mpa_rx.mbuf_arr[pind]);
+ }
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ if (f_do_rx_cur) {
+ /* Single Transfer pending */
+ /* Free curr buff also */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ }
+
+ LEAVE();
+ return ret;
+
+}
+#endif
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/**
+ * @brief This function sends data to the card in SDIO aggregated mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mbuf A pointer to the SDIO data/cmd buffer
+ * @param port current port for aggregation
+ * @param next_pkt_len Length of next packet used for multiport aggregation
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_host_to_card_mp_aggr(mlan_adapter * pmadapter, mlan_buffer * mbuf,
+ t_u8 port, t_u32 next_pkt_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_s32 f_send_aggr_buf = 0;
+ t_s32 f_send_cur_buf = 0;
+ t_s32 f_precopy_cur_buf = 0;
+ t_s32 f_postcopy_cur_buf = 0;
+ t_u32 cmd53_port = 0;
+ mlan_buffer mbuf_aggr;
+
+ ENTER();
+
+ PRINTM(MIF_D, "host_2_card_mp_aggr: next_pkt_len: %d curr_port:%d\n",
+ next_pkt_len, port);
+
+ if (!pmadapter->mpa_tx.enabled) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: tx aggregation disabled !\n");
+
+ f_send_cur_buf = 1;
+ goto tx_curr_single;
+ }
+
+ if (next_pkt_len) {
+ /* More pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: More packets in Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (!MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter) &&
+ MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+
+ if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port))
+ || !MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
+ mbuf->data_len +
+ next_pkt_len)) {
+ f_send_aggr_buf = 1;
+ }
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter) ||
+ !(pmadapter->
+ mp_wr_bitmap & (1 << pmadapter->curr_wr_port))) {
+ f_send_cur_buf = 1;
+ } else {
+ f_postcopy_cur_buf = 1;
+ }
+ }
+ } else {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len) &&
+ (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
+ f_precopy_cur_buf = 1;
+ else
+ f_send_cur_buf = 1;
+ }
+ } else {
+ /* Last pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: Last packet in Tx Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* some packs in Aggr buf already */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_cur_buf = 1;
+ }
+ } else {
+ f_send_cur_buf = 1;
+ }
+ }
+
+ if (f_precopy_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Precopy current buffer\n");
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+
+ if (MP_TX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MIF_D,
+ "host_2_card_mp_aggr: Aggregation Pkt limit reached\n");
+ /* No more pkts allowed in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+ }
+ }
+
+ if (f_send_aggr_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Send aggregation buffer."
+ "%d %d\n", pmadapter->mpa_tx.start_port,
+ pmadapter->mpa_tx.ports);
+
+ memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_tx.buf;
+ mbuf_aggr.data_len = pmadapter->mpa_tx.buf_len;
+ cmd53_port = (pmadapter->ioport | SDIO_MPA_ADDR_BASE |
+ (pmadapter->mpa_tx.ports << 4)) +
+ pmadapter->mpa_tx.start_port;
+ ret = wlan_write_data_sync(pmadapter, &mbuf_aggr, cmd53_port);
+ MP_TX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ tx_curr_single:
+ if (f_send_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: writing to port #%d\n", port);
+ ret = wlan_write_data_sync(pmadapter, mbuf, pmadapter->ioport + port);
+ }
+ if (f_postcopy_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Postcopy current buffer\n");
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function checks if the interface is ready to download
+ * or not while other download interface is present
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param val Winner status (0: winner)
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_check_winner_status(mlan_adapter * pmadapter, t_u32 * val)
+{
+ t_u32 winner = 0;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS0_REG,
+ &winner)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ *val = winner;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the firmware is ready to accept
+ * command or not.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pollnum Maximum polling number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_check_fw_status(mlan_adapter * pmadapter, t_u32 pollnum)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 firmwarestat;
+ t_u32 tries;
+
+ ENTER();
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (MLAN_STATUS_SUCCESS !=
+ (ret = wlan_sdio_read_fw_status(pmadapter, &firmwarestat)))
+ continue;
+ if (firmwarestat == FIRMWARE_READY) {
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ } else {
+ wlan_mdelay(pmadapter, 100);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware to card
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Download the firmware image via helper */
+ ret = wlan_prog_fw_w_helper(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function probes the driver
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_probe(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sdio_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ /*
+ * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+ * from the bootloader. If we don't do this we get a interrupt
+ * as soon as we register the irq.
+ */
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_STATUS_REG,
+ &sdio_ireg);
+
+ /* Disable host interrupt mask register for SDIO */
+ ret = wlan_disable_host_int(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Get SDIO ioport */
+ ret = wlan_sdio_init_ioport(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return N/A
+ */
+t_void
+wlan_interrupt(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer mbuf;
+ t_u32 sdio_ireg = 0;
+
+ ENTER();
+
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = pmadapter->mp_regs;
+ mbuf.data_len = MAX_MP_REGS;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
+ REG_PORT | MLAN_SDIO_BYTE_MODE_MASK, 0)) {
+ PRINTM(MERROR, "moal_read_data_sync: read registers failed\n");
+ pmadapter->dbg.num_int_read_failure++;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO MP Registers", pmadapter->mp_regs, MAX_MP_REGS);
+ sdio_ireg = pmadapter->mp_regs[HOST_INT_STATUS_REG];
+ pmadapter->dbg.last_int_status = pmadapter->sdio_ireg | sdio_ireg;
+ if (sdio_ireg) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
+ * UP_LD_CMD_PORT_HOST_INT_STATUS
+ * Clear the interrupt status register
+ */
+ PRINTM(MINTR, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ pmadapter->sdio_ireg |= sdio_ireg;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ } else {
+ PRINTM(MMSG, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
+ }
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_enable_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_enable_host_int_mask(pmadapter, HIM_ENABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the interrupt status and handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_int_status(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 sdio_ireg;
+ mlan_buffer *pmbuf = MNULL;
+ t_u8 port = 0;
+ t_u32 len_reg_l, len_reg_u;
+ t_u32 rx_blocks;
+ t_u32 ps_state = pmadapter->ps_state;
+ t_u16 rx_len;
+#if !defined(SDIO_MULTI_PORT_RX_AGGR)
+ t_u32 upld_typ = 0;
+#endif
+ t_u32 cr = 0;
+
+ ENTER();
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ sdio_ireg = pmadapter->sdio_ireg;
+ pmadapter->sdio_ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+
+ if (!sdio_ireg)
+ goto done;
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ pmadapter->mp_wr_bitmap = (t_u32) pmadapter->mp_regs[WR_BITMAP_L];
+ pmadapter->mp_wr_bitmap |=
+ ((t_u32) pmadapter->mp_regs[WR_BITMAP_U]) << 8;
+ PRINTM(MINTR, "DNLD: wr_bitmap=0x%08x\n", pmadapter->mp_wr_bitmap);
+ if (pmadapter->data_sent &&
+ (pmadapter->mp_wr_bitmap & pmadapter->mp_data_port_mask)) {
+ PRINTM(MINFO, " <--- Tx DONE Interrupt --->\n");
+ pmadapter->data_sent = MFALSE;
+ }
+ }
+
+ /* As firmware will not generate download ready interrupt if the port
+ updated is command port only, cmd_sent should be done for any SDIO
+ interrupt. */
+ if (pmadapter->cmd_sent == MTRUE) {
+ /* Check if firmware has attach buffer at command port and update just
+ that in wr_bit_map. */
+ pmadapter->mp_wr_bitmap |=
+ (t_u32) pmadapter->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
+ if (pmadapter->mp_wr_bitmap & CTRL_PORT_MASK)
+ pmadapter->cmd_sent = MFALSE;
+ }
+
+ PRINTM(MINFO, "cmd_sent=%d, data_sent=%d\n", pmadapter->cmd_sent,
+ pmadapter->data_sent);
+
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+ pmadapter->mp_rd_bitmap = (t_u32) pmadapter->mp_regs[RD_BITMAP_L];
+ pmadapter->mp_rd_bitmap |=
+ ((t_u32) pmadapter->mp_regs[RD_BITMAP_U]) << 8;
+ PRINTM(MINTR, "UPLD: rd_bitmap=0x%08x\n", pmadapter->mp_rd_bitmap);
+
+ while (MTRUE) {
+ ret = wlan_get_rd_port(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "no more rd_port to be handled\n");
+ break;
+ }
+ len_reg_l = RD_LEN_P0_L + (port << 1);
+ len_reg_u = RD_LEN_P0_U + (port << 1);
+ rx_len = ((t_u16) pmadapter->mp_regs[len_reg_u]) << 8;
+ rx_len |= (t_u16) pmadapter->mp_regs[len_reg_l];
+ PRINTM(MINFO, "RX: port=%d rx_len=%u\n", port, rx_len);
+ rx_blocks =
+ (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) / MLAN_SDIO_BLOCK_SIZE;
+ if (rx_len <= INTF_HEADER_LEN ||
+ (rx_blocks * MLAN_SDIO_BLOCK_SIZE) > ALLOC_BUF_SIZE) {
+ PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_len = (t_u16) (rx_blocks * MLAN_SDIO_BLOCK_SIZE);
+ if (port == CTRL_PORT)
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, rx_len, 0, MTRUE);
+ else
+ pmbuf =
+ wlan_alloc_mlan_buffer(pmadapter, rx_len,
+ MLAN_RX_HEADER_LEN, MFALSE);
+ if (pmbuf == MNULL) {
+ PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MINFO, "rx_len = %d\n", rx_len);
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host_mp_aggr(pmadapter, pmbuf, port,
+ rx_len)) {
+#else
+ /* Transfer data from card */
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(pmadapter, &upld_typ,
+ (t_u32 *) & pmadapter->upld_len, pmbuf,
+ rx_len, pmadapter->ioport + port)) {
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ if (port == CTRL_PORT)
+ pmadapter->dbg.num_cmdevt_card_to_host_failure++;
+ else
+ pmadapter->dbg.num_rx_card_to_host_failure++;
+
+ PRINTM(MERROR, "Card to host failed: int status=0x%x\n",
+ sdio_ireg);
+#ifndef SDIO_MULTI_PORT_RX_AGGR
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+#endif
+ ret = MLAN_STATUS_FAILURE;
+ goto term_cmd53;
+ }
+#ifndef SDIO_MULTI_PORT_RX_AGGR
+ wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ);
+#endif
+ }
+ /* We might receive data/sleep_cfm at the same time */
+ /* reset data_receive flag to avoid ps_state change */
+ if ((ps_state == PS_STATE_SLEEP_CFM) &&
+ (pmadapter->ps_state == PS_STATE_SLEEP))
+ pmadapter->data_received = MFALSE;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+
+ term_cmd53:
+ /* terminate cmd53 */
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+ PRINTM(MINFO, "Config Reg val = %d\n", cr);
+ if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ (cr | HOST_TERM_CMD53)))
+ PRINTM(MERROR, "write CFG reg failed\n");
+ PRINTM(MINFO, "write success\n");
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+ PRINTM(MINFO, "Config reg val =%x\n", cr);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
+ * @param tx_param A pointer to mlan_tx_param
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type, mlan_buffer * pmbuf,
+ mlan_tx_param * tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 buf_block_len;
+ t_u32 blksz;
+ t_u8 port = 0;
+ t_u32 cmd53_port = 0;
+ t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
+
+ ENTER();
+
+ /* Allocate buffer and copy payload */
+ blksz = MLAN_SDIO_BLOCK_SIZE;
+ buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
+ *(t_u16 *) & payload[0] = wlan_cpu_to_le16((t_u16) pmbuf->data_len);
+ *(t_u16 *) & payload[2] = wlan_cpu_to_le16(type);
+
+ /*
+ * This is SDIO specific header
+ * t_u16 length,
+ * t_u16 type (MLAN_TYPE_DATA = 0, MLAN_TYPE_CMD = 1, MLAN_TYPE_EVENT = 3)
+ */
+ if (type == MLAN_TYPE_DATA) {
+ ret = wlan_get_wr_port_data(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "no wr_port available: %d\n", ret);
+ goto exit;
+ }
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ if (tx_param)
+ ret =
+ wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
+ tx_param->next_pkt_len);
+ else
+ ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port, 0);
+#else
+ ret = wlan_write_data_sync(pmadapter, pmbuf, pmadapter->ioport + port);
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+ } else {
+ /* Type must be MLAN_TYPE_CMD */
+ pmadapter->cmd_sent = MTRUE;
+ /* clear CTRL PORT */
+ pmadapter->mp_wr_bitmap &= (t_u32) (~(1 << CTRL_PORT));
+ if (pmbuf->data_len <= INTF_HEADER_LEN ||
+ pmbuf->data_len > WLAN_UPLD_SIZE)
+ PRINTM(MWARN,
+ "wlan_sdio_host_to_card(): Error: payload=%p, nb=%d\n",
+ payload, pmbuf->data_len);
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+ cmd53_port = pmadapter->ioport + CTRL_PORT;
+ ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
+ }
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (type == MLAN_TYPE_CMD)
+ pmadapter->cmd_sent = MFALSE;
+ if (type == MLAN_TYPE_DATA)
+ pmadapter->data_sent = MFALSE;
+ } else {
+ if (type == MLAN_TYPE_DATA) {
+ if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
+ pmadapter->data_sent = MTRUE;
+ else
+ pmadapter->data_sent = MFALSE;
+ }
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Wr", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+ }
+ exit:
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief This function allocates buffer for the SDIO aggregation buffer
+ * related members of adapter structure
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mpa_tx_buf_size Tx buffer size to allocate
+ * @param mpa_rx_buf_size Rx buffer size to allocate
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
+ t_u32 mpa_tx_buf_size, t_u32 mpa_rx_buf_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ mpa_tx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **) & pmadapter->mpa_tx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_tx.head_ptr) {
+ PRINTM(MERROR, "Could not allocate buffer for SDIO MP TX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->mpa_tx.buf =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mpa_tx.head_ptr, DMA_ALIGNMENT);
+ pmadapter->mpa_tx.buf_size = mpa_tx_buf_size;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ mpa_rx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **) & pmadapter->mpa_rx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_rx.head_ptr) {
+ PRINTM(MERROR, "Could not allocate buffer for SDIO MP RX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->mpa_rx.buf =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mpa_rx.head_ptr, DMA_ALIGNMENT);
+ pmadapter->mpa_rx.buf_size = mpa_rx_buf_size;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+ error:
+ if (ret != MLAN_STATUS_SUCCESS) {
+ wlan_free_sdio_mpa_buffers(pmadapter);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees buffers for the SDIO aggregation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_free_sdio_mpa_buffers(IN mlan_adapter * pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ if (pmadapter->mpa_tx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->mpa_tx.head_ptr);
+ pmadapter->mpa_tx.head_ptr = MNULL;
+ pmadapter->mpa_tx.buf = MNULL;
+ pmadapter->mpa_tx.buf_size = 0;
+ }
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ if (pmadapter->mpa_rx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->mpa_rx.head_ptr);
+ pmadapter->mpa_rx.head_ptr = MNULL;
+ pmadapter->mpa_rx.buf = MNULL;
+ pmadapter->mpa_rx.buf_size = 0;
+ }
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_set_sdio_gpio_int(IN pmlan_private priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = priv->adapter;
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_int_cfg;
+
+ ENTER();
+
+ if (pmadapter->int_mode == INT_MODE_GPIO) {
+ PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is GPIO\n");
+ sdio_int_cfg.action = HostCmd_ACT_GEN_SET;
+ sdio_int_cfg.gpio_pin = pmadapter->gpio_pin;
+ sdio_int_cfg.gpio_int_edge = INT_FALLING_EDGE;
+ sdio_int_cfg.gpio_pulse_width = DELAY_1_US;
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_SDIO_GPIO_INT_CONFIG,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &sdio_int_cfg);
+
+ if (ret) {
+ PRINTM(MERROR, "SDIO_GPIO_INT_CONFIG: send command fail\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is SDIO\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of SDIO GPIO interrupt
+ *
+ * @param pmpriv 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_sdio_gpio_int(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG *psdio_gpio_int =
+ &cmd->params.sdio_gpio_int;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_GPIO_INT_CONFIG);
+ cmd->size =
+ wlan_cpu_to_le16((sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG)) + S_DS_GEN);
+
+ memset(pmpriv->adapter, psdio_gpio_int, 0,
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy(pmpriv->adapter, psdio_gpio_int, pdata_buf,
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
+ psdio_gpio_int->action = wlan_cpu_to_le16(psdio_gpio_int->action);
+ psdio_gpio_int->gpio_pin = wlan_cpu_to_le16(psdio_gpio_int->gpio_pin);
+ psdio_gpio_int->gpio_int_edge =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_int_edge);
+ psdio_gpio_int->gpio_pulse_width =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_pulse_width);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sdio.h b/drivers/net/wireless/sd8797/mlan/mlan_sdio.h
new file mode 100644
index 000000000000..f77397d66eb4
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sdio.h
@@ -0,0 +1,307 @@
+/** @file mlan_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ * 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:
+****************************************************/
+
+#ifndef _MLAN_SDIO_H
+#define _MLAN_SDIO_H
+
+/** Block mode */
+#define BLOCK_MODE 1
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+
+/* Host Control Registers */
+/** Host Control Registers : Host to Card Event */
+#define HOST_TO_CARD_EVENT_REG 0x00
+/** Host Control Registers : Host terminates Command 53 */
+#define HOST_TERM_CMD53 (0x1U << 2)
+/** Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
+/** Host Control Registers : Host power up */
+#define HOST_POWER_UP (0x1U << 1)
+/** Host Control Registers : Host power down */
+#define HOST_POWER_DOWN (0x1U << 0)
+
+/** Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG 0x01
+/** Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR (0x1U)
+#define HOST_INT_RSR_MASK 0x3F
+
+/** Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG 0x02
+/** Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK (0x1U)
+/** Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK (0x2U)
+/** Enable Host interrupt mask */
+#define HIM_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+/** Disable Host interrupt mask */
+#define HIM_DISABLE 0xff
+
+/** Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG 0x03
+/** Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS (0x1U)
+/** Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS (0x2U)
+
+/** Port for registers */
+#define REG_PORT 0
+/** LSB of read bitmap */
+#define RD_BITMAP_L 0x04
+/** MSB of read bitmap */
+#define RD_BITMAP_U 0x05
+/** LSB of write bitmap */
+#define WR_BITMAP_L 0x06
+/** MSB of write bitmap */
+#define WR_BITMAP_U 0x07
+/** LSB of read length for port 0 */
+#define RD_LEN_P0_L 0x08
+/** MSB of read length for port 0 */
+#define RD_LEN_P0_U 0x09
+/** Ctrl port */
+#define CTRL_PORT 0
+/** Ctrl port mask */
+#define CTRL_PORT_MASK 0x0001
+/** Data port mask */
+#define DATA_PORT_MASK 0xfffe
+/** Misc. Config Register : Auto Re-enable interrupts */
+#define AUTO_RE_ENABLE_INT MBIT(4)
+
+/** Host Control Registers : Host transfer status */
+#define HOST_RESTART_REG 0x28
+/** Host Control Registers : Download CRC error */
+#define DN_LD_CRC_ERR (0x1U << 2)
+/** Host Control Registers : Upload restart */
+#define UP_LD_RESTART (0x1U << 1)
+/** Host Control Registers : Download restart */
+#define DN_LD_RESTART (0x1U << 0)
+
+/* Card Control Registers */
+/** Card Control Registers : Card to host event */
+#define CARD_TO_HOST_EVENT_REG 0x30
+/** Card Control Registers : Card I/O ready */
+#define CARD_IO_READY (0x1U << 3)
+/** Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY (0x1U << 2)
+/** Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY (0x1U << 1)
+/** Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY (0x1U << 0)
+
+/** Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG 0x34
+/** Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK (0x1U << 3)
+/** Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK (0x1U << 2)
+/** Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK (0x1U << 1)
+/** Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK (0x1U << 0)
+
+/** Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG 0x38
+/** Card Control Registers : Power up interrupt */
+#define POWER_UP_INT (0x1U << 4)
+/** Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT (0x1U << 3)
+
+/** Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG 0x3c
+/** Card Control Registers : Power up RSR */
+#define POWER_UP_RSR (0x1U << 4)
+/** Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR (0x1U << 3)
+
+/** Card Control Registers : SQ Read base address 0 register */
+#define READ_BASE_0_REG 0x40
+/** Card Control Registers : SQ Read base address 1 register */
+#define READ_BASE_1_REG 0x41
+
+/** Card Control Registers : Card revision register */
+#define CARD_REVISION_REG 0x5c
+
+/** Firmware status 0 register (SCRATCH0_0) */
+#define CARD_FW_STATUS0_REG 0x60
+/** Firmware status 1 register (SCRATCH0_1) */
+#define CARD_FW_STATUS1_REG 0x61
+/** Rx length register (SCRATCH0_2) */
+#define CARD_RX_LEN_REG 0x62
+/** Rx unit register (SCRATCH0_3) */
+#define CARD_RX_UNIT_REG 0x63
+
+/** Card Control Registers : Card OCR 0 register */
+#define CARD_OCR_0_REG 0x68
+/** Card Control Registers : Card OCR 1 register */
+#define CARD_OCR_1_REG 0x69
+/** Card Control Registers : Card OCR 3 register */
+#define CARD_OCR_3_REG 0x6A
+/** Card Control Registers : Card config register */
+#define CARD_CONFIG_REG 0x6B
+/** Card Control Registers : Miscellaneous Configuration Register */
+#define CARD_MISC_CFG_REG 0x6C
+
+/** Card Control Registers : Debug 0 register */
+#define DEBUG_0_REG 0x70
+/** Card Control Registers : SD test BUS 0 */
+#define SD_TESTBUS0 (0x1U)
+/** Card Control Registers : Debug 1 register */
+#define DEBUG_1_REG 0x71
+/** Card Control Registers : SD test BUS 1 */
+#define SD_TESTBUS1 (0x1U)
+/** Card Control Registers : Debug 2 register */
+#define DEBUG_2_REG 0x72
+/** Card Control Registers : SD test BUS 2 */
+#define SD_TESTBUS2 (0x1U)
+/** Card Control Registers : Debug 3 register */
+#define DEBUG_3_REG 0x73
+/** Card Control Registers : SD test BUS 3 */
+#define SD_TESTBUS3 (0x1U)
+
+/** Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG 0x78
+/** Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG 0x79
+/** Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG 0x7A
+
+/** Event header Len*/
+#define MLAN_EVENT_HEADER_LEN 8
+
+/** SDIO byte mode size */
+#define MAX_BYTE_MODE_SIZE 512
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** The base address for packet with multiple ports aggregation */
+#define SDIO_MPA_ADDR_BASE 0x1000
+#endif
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+
+/** SDIO Tx aggregation in progress ? */
+#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt>0)
+
+/** SDIO Tx aggregation buffer room for next packet ? */
+#define MP_TX_AGGR_BUF_HAS_ROOM(a,mbuf, len) ((a->mpa_tx.buf_len+len)<= a->mpa_tx.buf_size)
+
+/** Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
+#define MP_TX_AGGR_BUF_PUT(a, mbuf, port) do{ \
+ pmadapter->callbacks.moal_memmove(a->pmoal_handle, &a->mpa_tx.buf[a->mpa_tx.buf_len],mbuf->pbuf+mbuf->data_offset,mbuf->data_len);\
+ a->mpa_tx.buf_len += mbuf->data_len; \
+ if(!a->mpa_tx.pkt_cnt){ \
+ a->mpa_tx.start_port = port; \
+ } \
+ if(a->mpa_tx.start_port<=port){ \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
+ }else{ \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - a->mp_end_port))); \
+ } \
+ a->mpa_tx.pkt_cnt++; \
+}while(0);
+
+/** SDIO Tx aggregation limit ? */
+#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) (a->mpa_tx.pkt_cnt==a->mpa_tx.pkt_aggr_limit)
+
+/** SDIO Tx aggregation port limit ? */
+#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
+ a->mpa_tx.start_port) && (((MAX_PORT - \
+ a->mpa_tx.start_port) + a->curr_wr_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/** Reset SDIO Tx aggregation buffer parameters */
+#define MP_TX_AGGR_BUF_RESET(a) do{ \
+ a->mpa_tx.pkt_cnt = 0; \
+ a->mpa_tx.buf_len = 0; \
+ a->mpa_tx.ports = 0; \
+ a->mpa_tx.start_port = 0; \
+} while(0);
+
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+
+/** SDIO Rx aggregation limit ? */
+#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) (a->mpa_rx.pkt_cnt== a->mpa_rx.pkt_aggr_limit)
+
+/** SDIO Rx aggregation port limit ? */
+#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
+ a->mpa_rx.start_port) && (((MAX_PORT - \
+ a->mpa_rx.start_port) + a->curr_rd_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/** SDIO Rx aggregation in progress ? */
+#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt>0)
+
+/** SDIO Rx aggregation buffer room for next packet ? */
+#define MP_RX_AGGR_BUF_HAS_ROOM(a,rx_len) ((a->mpa_rx.buf_len+rx_len)<=a->mpa_rx.buf_size)
+
+/** Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+#define MP_RX_AGGR_SETUP(a, mbuf, port, rx_len) do{ \
+ a->mpa_rx.buf_len += rx_len; \
+ if(!a->mpa_rx.pkt_cnt){ \
+ a->mpa_rx.start_port = port; \
+ } \
+ if(a->mpa_rx.start_port<=port){ \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
+ }else{ \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
+ } \
+ a->mpa_rx.mbuf_arr[a->mpa_rx.pkt_cnt] = mbuf; \
+ a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = rx_len; \
+ a->mpa_rx.pkt_cnt++; \
+}while(0);
+
+/** Reset SDIO Rx aggregation buffer parameters */
+#define MP_RX_AGGR_BUF_RESET(a) do{ \
+ a->mpa_rx.pkt_cnt = 0; \
+ a->mpa_rx.buf_len = 0; \
+ a->mpa_rx.ports = 0; \
+ a->mpa_rx.start_port = 0; \
+} while(0);
+
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** Enable host interrupt */
+mlan_status wlan_enable_host_int(pmlan_adapter pmadapter);
+/** Probe and initialization function */
+mlan_status wlan_sdio_probe(pmlan_adapter pmadapter);
+/** multi interface download check */
+mlan_status wlan_check_winner_status(mlan_adapter * pmadapter, t_u32 * val);
+/** Firmware status check */
+mlan_status wlan_check_fw_status(mlan_adapter * pmadapter, t_u32 pollnum);
+/** Read interrupt status */
+t_void wlan_interrupt(pmlan_adapter pmadapter);
+/** Process Interrupt Status */
+mlan_status wlan_process_int_status(mlan_adapter * pmadapter);
+/** Transfer data to card */
+mlan_status wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type,
+ mlan_buffer * mbuf,
+ mlan_tx_param * tx_param);
+mlan_status wlan_set_sdio_gpio_int(IN pmlan_private priv);
+mlan_status wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+#endif /* _MLAN_SDIO_H */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_shim.c b/drivers/net/wireless/sd8797/mlan/mlan_shim.c
new file mode 100644
index 000000000000..07f7db5c7227
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_shim.c
@@ -0,0 +1,946 @@
+/** @file mlan_shim.c
+ *
+ * @brief This file contains APIs to MOAL module.
+ *
+ * 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
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+#ifdef STA_SUPPORT
+mlan_operations mlan_sta_ops = {
+ /* init cmd handler */
+ wlan_ops_sta_init_cmd,
+ /* ioctl handler */
+ wlan_ops_sta_ioctl,
+ /* cmd handler */
+ wlan_ops_sta_prepare_cmd,
+ /* cmdresp handler */
+ wlan_ops_sta_process_cmdresp,
+ /* rx handler */
+ wlan_ops_sta_process_rx_packet,
+ /* Event handler */
+ wlan_ops_sta_process_event,
+ /* txpd handler */
+ wlan_ops_sta_process_txpd,
+ /* BSS role: STA */
+ MLAN_BSS_ROLE_STA,
+};
+#endif
+#ifdef UAP_SUPPORT
+mlan_operations mlan_uap_ops = {
+ /* init cmd handler */
+ wlan_ops_uap_init_cmd,
+ /* ioctl handler */
+ wlan_ops_uap_ioctl,
+ /* cmd handler */
+ wlan_ops_uap_prepare_cmd,
+ /* cmdresp handler */
+ wlan_ops_uap_process_cmdresp,
+ /* rx handler */
+ wlan_ops_uap_process_rx_packet,
+ /* Event handler */
+ wlan_ops_uap_process_event,
+ /* txpd handler */
+ wlan_ops_uap_process_txpd,
+ /* BSS role: uAP */
+ MLAN_BSS_ROLE_UAP,
+};
+#endif
+
+/** mlan function table */
+mlan_operations *mlan_ops[] = {
+#ifdef STA_SUPPORT
+ &mlan_sta_ops,
+#endif
+#ifdef UAP_SUPPORT
+ &mlan_uap_ops,
+#endif
+ MNULL,
+};
+
+/** Global moal_assert callback */
+t_void(*assert_callback) (IN t_void * pmoal_handle, IN t_u32 cond) = MNULL;
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
+#endif
+
+/** Global moal_print callback */
+t_void(*print_callback) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...) = MNULL;
+
+/** Global moal_get_system_time callback */
+mlan_status(*get_sys_time_callback) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec,
+ OUT t_u32 * pusec) = MNULL;
+
+/** Global driver debug mit masks */
+t_u32 drvdbg = DEFAULT_DEBUG_MASK;
+#endif
+
+/********************************************************
+ Local Functions
+*******************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function registers MOAL to MLAN module.
+ *
+ * @param pmdevice A pointer to a mlan_device structure
+ * allocated in MOAL
+ * @param ppmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer as the context
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The registration succeeded.
+ * MLAN_STATUS_FAILURE
+ * The registration failed.
+ *
+ * mlan_status mlan_register (
+ * IN pmlan_device pmdevice,
+ * OUT t_void **ppmlan_adapter
+ * );
+ *
+ * Comments
+ * MOAL constructs mlan_device data structure to pass moal_handle and
+ * mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to
+ * the ppmlan_adapter buffer provided by MOAL.
+ * Headers:
+ * declared in mlan_decl.h
+ * See Also
+ * mlan_unregister
+ */
+mlan_status
+mlan_register(IN pmlan_device pmdevice, OUT t_void ** ppmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = MNULL;
+ pmlan_callbacks pcb = MNULL;
+ t_u8 i = 0;
+ t_u32 j = 0;
+
+ MASSERT(pmdevice);
+ MASSERT(ppmlan_adapter);
+ MASSERT(pmdevice->callbacks.moal_print);
+#ifdef DEBUG_LEVEL1
+ print_callback = pmdevice->callbacks.moal_print;
+ get_sys_time_callback = pmdevice->callbacks.moal_get_system_time;
+#endif
+ assert_callback = pmdevice->callbacks.moal_assert;
+
+ ENTER();
+
+ MASSERT(pmdevice->callbacks.moal_malloc);
+ MASSERT(pmdevice->callbacks.moal_memset);
+ MASSERT(pmdevice->callbacks.moal_memmove);
+
+ /* Allocate memory for adapter structure */
+ if ((pmdevice->callbacks.
+ moal_malloc(pmdevice->pmoal_handle, sizeof(mlan_adapter), MLAN_MEM_DEF,
+ (t_u8 **) & pmadapter) != MLAN_STATUS_SUCCESS)
+ || !pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_register;
+ }
+
+ pmdevice->callbacks.moal_memset(pmadapter, pmadapter,
+ 0, sizeof(mlan_adapter));
+
+ pcb = &pmadapter->callbacks;
+
+ /* Save callback functions */
+ pmdevice->callbacks.moal_memmove(pmadapter->pmoal_handle, pcb,
+ &pmdevice->callbacks,
+ sizeof(mlan_callbacks));
+
+ /* Assertion for all callback functions */
+ MASSERT(pcb->moal_init_fw_complete);
+ MASSERT(pcb->moal_shutdown_fw_complete);
+ MASSERT(pcb->moal_send_packet_complete);
+ MASSERT(pcb->moal_recv_packet);
+ MASSERT(pcb->moal_recv_event);
+ MASSERT(pcb->moal_ioctl_complete);
+ MASSERT(pcb->moal_write_reg);
+ MASSERT(pcb->moal_read_reg);
+ MASSERT(pcb->moal_alloc_mlan_buffer);
+ MASSERT(pcb->moal_free_mlan_buffer);
+ MASSERT(pcb->moal_write_data_sync);
+ MASSERT(pcb->moal_read_data_sync);
+ MASSERT(pcb->moal_mfree);
+ MASSERT(pcb->moal_memcpy);
+ MASSERT(pcb->moal_memcmp);
+ MASSERT(pcb->moal_get_system_time);
+ MASSERT(pcb->moal_init_timer);
+ MASSERT(pcb->moal_free_timer);
+ MASSERT(pcb->moal_start_timer);
+ MASSERT(pcb->moal_stop_timer);
+ MASSERT(pcb->moal_init_lock);
+ MASSERT(pcb->moal_free_lock);
+ MASSERT(pcb->moal_spin_lock);
+ MASSERT(pcb->moal_spin_unlock);
+
+ /* Save pmoal_handle */
+ pmadapter->pmoal_handle = pmdevice->pmoal_handle;
+
+ if ((pmdevice->int_mode == INT_MODE_GPIO) && (pmdevice->gpio_pin == 0)) {
+ PRINTM(MERROR, "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->init_para.int_mode = pmdevice->int_mode;
+ pmadapter->init_para.gpio_pin = pmdevice->gpio_pin;
+ /* card specific probing has been deferred until now .. */
+ if (MLAN_STATUS_SUCCESS != (ret = wlan_sdio_probe(pmadapter))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#ifdef DEBUG_LEVEL1
+ drvdbg = pmdevice->drvdbg;
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+ pmadapter->init_para.mfg_mode = pmdevice->mfg_mode;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ pmadapter->init_para.mpa_tx_cfg = pmdevice->mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ pmadapter->init_para.mpa_rx_cfg = pmdevice->mpa_rx_cfg;
+#endif
+ pmadapter->init_para.auto_ds = pmdevice->auto_ds;
+ pmadapter->init_para.ps_mode = pmdevice->ps_mode;
+ if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_8K)
+ pmadapter->init_para.max_tx_buf = pmdevice->max_tx_buf;
+#ifdef STA_SUPPORT
+ pmadapter->init_para.cfg_11d = pmdevice->cfg_11d;
+#else
+ pmadapter->init_para.cfg_11d = 0;
+#endif
+ pmadapter->init_para.dfs_master_radar_det_en = DFS_MASTER_RADAR_DETECT_EN;
+ pmadapter->init_para.dfs_slave_radar_det_en = DFS_SLAVE_RADAR_DETECT_EN;
+
+ pmadapter->priv_num = 0;
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ pmadapter->priv[i] = MNULL;
+ if (pmdevice->bss_attr[i].active == MTRUE) {
+ /* For valid bss_attr, allocate memory for private structure */
+ if ((pcb->
+ moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_private),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pmadapter->priv[i]) !=
+ MLAN_STATUS_SUCCESS)
+ || !pmadapter->priv[i]) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ pmadapter->priv_num++;
+ memset(pmadapter, pmadapter->priv[i], 0, sizeof(mlan_private));
+
+ pmadapter->priv[i]->adapter = pmadapter;
+
+ /* Save bss_type, frame_type & bss_priority */
+ pmadapter->priv[i]->bss_type =
+ (t_u8) pmdevice->bss_attr[i].bss_type;
+ pmadapter->priv[i]->frame_type =
+ (t_u8) pmdevice->bss_attr[i].frame_type;
+ pmadapter->priv[i]->bss_priority =
+ (t_u8) pmdevice->bss_attr[i].bss_priority;
+ if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_STA)
+ pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_STA;
+ else if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_UAP)
+ pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_UAP;
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_STA;
+#endif
+ /* Save bss_index and bss_num */
+ pmadapter->priv[i]->bss_index = i;
+ pmadapter->priv[i]->bss_num = (t_u8) pmdevice->bss_attr[i].bss_num;
+
+ /* init function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmadapter->priv[i])) {
+ memcpy(pmadapter, &pmadapter->priv[i]->ops, mlan_ops[j],
+ sizeof(mlan_operations));
+ }
+ }
+ }
+ }
+
+ /* Initialize lock variables */
+ if (wlan_init_lock_list(pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /* Allocate memory for member of adapter structure */
+ if (wlan_allocate_adapter(pmadapter)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /* Initialize timers */
+ if (wlan_init_timer(pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ /* Return pointer of mlan_adapter to MOAL */
+ *ppmlan_adapter = pmadapter;
+
+ goto exit_register;
+
+ error:
+ PRINTM(MINFO, "Leave mlan_register with error\n");
+ /* Free timers */
+ wlan_free_timer(pmadapter);
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+ /* Free lock variables */
+ wlan_free_lock_list(pmadapter);
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i])
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->priv[i]);
+ }
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter);
+
+ exit_register:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function unregisters MOAL from MLAN module.
+ *
+ * @param pmlan_adapter A pointer to a mlan_device structure
+ * allocated in MOAL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The deregistration succeeded.
+ */
+mlan_status
+mlan_unregister(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ MASSERT(pmlan_adapter);
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+
+ /* Free timers */
+ wlan_free_timer(pmadapter);
+
+ /* Free lock variables */
+ wlan_free_lock_list(pmadapter);
+
+ /* Free private structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->priv[i]);
+ }
+ }
+
+ /* Free mlan_adapter */
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware download succeeded.
+ * MLAN_STATUS_FAILURE
+ * The firmware download failed.
+ */
+mlan_status
+mlan_dnld_fw(IN t_void * pmlan_adapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ t_u32 poll_num = 1;
+ t_u32 winner = 0;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ /* Card specific probing */
+ ret = wlan_sdio_probe(pmadapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "WLAN SDIO probe failed\n", ret);
+ LEAVE();
+ return ret;
+ }
+
+ /* Check if firmware is already running */
+ ret = wlan_check_fw_status(pmadapter, poll_num);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG, "WLAN FW already running! Skip FW download\n");
+ goto done;
+ }
+ poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ /* Check if other interface is downloading */
+ ret = wlan_check_winner_status(pmadapter, &winner);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MFATAL, "WLAN read winner status failed!\n");
+ goto done;
+ }
+ if (winner) {
+ PRINTM(MMSG, "WLAN is not the winner (0x%x). Skip FW download\n",
+ winner);
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+
+ if (pmfw) {
+ /* Download helper/firmware */
+ ret = wlan_dnld_fw(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
+ LEAVE();
+ return ret;
+ }
+ }
+
+ poll_fw:
+ /* Check if the firmware is downloaded successfully or not */
+ ret = wlan_check_fw_status(pmadapter, poll_num);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "FW failed to be active in time!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ done:
+
+ /* re-enable host interrupt for mlan after fw dnld is successful */
+ wlan_enable_host_int(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function pass init param to MLAN
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pparam A pointer to mlan_init_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ */
+mlan_status
+mlan_set_init_param(IN t_void * pmlan_adapter, IN pmlan_init_param pparam)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ /** Save cal data in MLAN */
+ if ((pparam->pcal_data_buf) && (pparam->cal_data_len > 0)) {
+ pmadapter->pcal_data = pparam->pcal_data_buf;
+ pmadapter->cal_data_len = pparam->cal_data_len;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware initialization is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware initialization failed.
+ */
+mlan_status
+mlan_init_fw(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ /* Initialize firmware, may return PENDING */
+ ret = wlan_init_fw(pmadapter);
+ PRINTM(MINFO, "wlan_init_fw returned ret=0x%x\n", ret);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Shutdown firmware
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown call succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware shutdown call is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware shutdown call failed.
+ */
+mlan_status
+mlan_shutdown_fw(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+ /* mlan already shutdown */
+ if (pmadapter->hw_status == WlanHardwareStatusNotReady) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ pmadapter->hw_status = WlanHardwareStatusClosing;
+ /* wait for mlan_process to complete */
+ if (pmadapter->mlan_processing) {
+ PRINTM(MWARN, "mlan main processing is still running\n");
+ LEAVE();
+ return ret;
+ }
+
+ /* shut down mlan */
+ PRINTM(MINFO, "Shutdown mlan...\n");
+
+ /* Clean up priv structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ wlan_free_priv(pmadapter->priv[i]);
+ }
+ }
+
+ pcb = &pmadapter->callbacks;
+
+ if (pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_shutdown_fw;
+ }
+
+ if (pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_shutdown_fw;
+ }
+
+ /* Notify completion */
+ ret = wlan_shutdown_fw_complete(pmadapter);
+
+ exit_shutdown_fw:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The main process
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_main_process(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmlan_adapter);
+
+ pcb = &pmadapter->callbacks;
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_processing) {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ goto exit_main_proc;
+ } else {
+ pmadapter->mlan_processing = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ }
+ process_start:
+ do {
+ /* Is MLAN shutting down or not ready? */
+ if ((pmadapter->hw_status == WlanHardwareStatusClosing) ||
+ (pmadapter->hw_status == WlanHardwareStatusNotReady))
+ break;
+
+ /* Handle pending SDIO interrupts if any */
+ if (pmadapter->sdio_ireg) {
+ if (pmadapter->hs_activated == MTRUE)
+ wlan_process_hs_config(pmadapter);
+ wlan_process_int_status(pmadapter);
+ }
+
+ /* Need to wake up the card ? */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP) &&
+ (pmadapter->pm_wakeup_card_req &&
+ !pmadapter->pm_wakeup_fw_try) &&
+ (util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)
+ || !wlan_bypass_tx_list_empty(pmadapter)
+ || !wlan_wmm_lists_empty(pmadapter)
+ )) {
+ pmadapter->pm_wakeup_fw_try = MTRUE;
+ wlan_pm_wakeup_card(pmadapter);
+ continue;
+ }
+ if (IS_CARD_RX_RCVD(pmadapter)) {
+ pmadapter->data_received = MFALSE;
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ if (pmadapter->ps_state == PS_STATE_SLEEP)
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ } else {
+ /* We have tried to wakeup the card already */
+ if (pmadapter->pm_wakeup_fw_try)
+ break;
+ if (pmadapter->ps_state != PS_STATE_AWAKE ||
+ (pmadapter->tx_lock_flag == MTRUE))
+ break;
+
+ if (pmadapter->scan_processing || pmadapter->data_sent
+ || (wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter))
+ || wlan_11h_radar_detected_tx_blocked(pmadapter)
+ ) {
+ if (pmadapter->cmd_sent || pmadapter->curr_cmd ||
+ (!util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
+ break;
+ }
+ }
+ }
+
+ /* Check for Cmd Resp */
+ if (pmadapter->cmd_resp_received) {
+ pmadapter->cmd_resp_received = MFALSE;
+ wlan_process_cmdresp(pmadapter);
+
+ /* call moal back when init_fw is done */
+ if (pmadapter->hw_status == WlanHardwareStatusInitdone) {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ wlan_init_fw_complete(pmadapter);
+ }
+ }
+
+ /* Check for event */
+ if (pmadapter->event_received) {
+ pmadapter->event_received = MFALSE;
+ wlan_process_event(pmadapter);
+ }
+
+ /* Check if we need to confirm Sleep Request received previously */
+ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) {
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ wlan_check_ps_cond(pmadapter);
+ }
+ }
+
+ /*
+ * The ps_state may have been changed during processing of
+ * Sleep Request event.
+ */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP)
+ || (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
+ || (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ || (pmadapter->tx_lock_flag == MTRUE)
+ )
+ continue;
+
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ if (wlan_exec_next_cmd(pmadapter) == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (!pmadapter->scan_processing && !pmadapter->data_sent &&
+ !wlan_11h_radar_detected_tx_blocked(pmadapter) &&
+ !wlan_bypass_tx_list_empty(pmadapter)) {
+ PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n");
+ wlan_process_bypass_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ }
+
+ if (!pmadapter->scan_processing && !pmadapter->data_sent &&
+ !wlan_wmm_lists_empty(pmadapter)
+ && !wlan_11h_radar_detected_tx_blocked(pmadapter)
+ ) {
+ wlan_wmm_process_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ }
+
+#ifdef STA_SUPPORT
+ if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !IS_COMMAND_PENDING(pmadapter) &&
+ wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter)) {
+ if (wlan_send_null_packet
+ (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA),
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
+ == MLAN_STATUS_SUCCESS) {
+ pmadapter->delay_null_pkt = MFALSE;
+ }
+ break;
+ }
+#endif
+
+ } while (MTRUE);
+
+ if ((pmadapter->sdio_ireg) || IS_CARD_RX_RCVD(pmadapter)) {
+ goto process_start;
+ }
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock);
+ pmadapter->mlan_processing = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock);
+
+ exit_main_proc:
+ if (pmadapter->hw_status == WlanHardwareStatusClosing)
+ mlan_shutdown_fw(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Function to send packet
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ *
+ * @return MLAN_STATUS_PENDING
+ */
+mlan_status
+mlan_send_packet(IN t_void * pmlan_adapter, IN pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter && pmbuf);
+
+ MASSERT(pmbuf->bss_index < pmadapter->priv_num);
+ pmbuf->flags = MLAN_BUF_FLAG_MOAL_TX_BUF;
+
+ if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) &&
+ ((mlan_ntohs(*(t_u16 *) & pmbuf->pbuf[pmbuf->data_offset +
+ MLAN_ETHER_PKT_TYPE_OFFSET]) ==
+ MLAN_ETHER_PKT_TYPE_EAPOL)
+ ||
+ (mlan_ntohs
+ (*(t_u16 *) & pmbuf->
+ pbuf[pmbuf->data_offset + MLAN_ETHER_PKT_TYPE_OFFSET]) ==
+ MLAN_ETHER_PKT_TYPE_WAPI)
+ ))
+ || (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)
+
+ ) {
+ PRINTM(MINFO, "mlan_send_pkt(): enq(bybass_txq)\n");
+ wlan_add_buf_bypass_txqueue(pmadapter, pmbuf);
+ } else {
+ /* Transmit the packet */
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+mlan_ioctl(IN t_void * adapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ pmlan_private pmpriv = MNULL;
+
+ ENTER();
+
+ if (pioctl_req == MNULL) {
+ PRINTM(MERROR, "MLAN IOCTL information buffer is NULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (pioctl_req->action == MLAN_ACT_CANCEL) {
+ wlan_cancel_pending_ioctl(pmadapter, pioctl_req);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ ret = pmpriv->ops.ioctl(adapter, pioctl_req);
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+mlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ wlan_recv_packet_complete(pmadapter, pmbuf, status);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief select wmm queue
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param bss_num BSS number
+ * @param tid TID
+ *
+ * @return wmm queue priority (0 - 3)
+ */
+t_u8
+mlan_select_wmm_queue(IN t_void * pmlan_adapter, IN t_u8 bss_num, IN t_u8 tid)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_private pmpriv = pmadapter->priv[bss_num];
+ t_u8 ret;
+ ENTER();
+ ret = wlan_wmm_select_queue(pmpriv, tid);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @return N/A
+ */
+t_void
+mlan_interrupt(IN t_void * adapter)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) adapter;
+
+ ENTER();
+ if (!pmadapter->pps_uapsd_mode && pmadapter->ps_state == PS_STATE_SLEEP) {
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ }
+ wlan_interrupt(pmadapter);
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
new file mode 100644
index 000000000000..7c426595117e
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
@@ -0,0 +1,1996 @@
+/** @file mlan_sta_cmd.c
+ *
+ * @brief This file contains the handling of command.
+ * it prepares command and sends it to firmware when
+ * it is ready.
+ *
+ * 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/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_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_sdio.h"
+#include "mlan_meas.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function prepares command of RSSI info.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_rssi_info(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_u16 cmd_action)
+{
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_RSSI_INFO);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI_INFO) + S_DS_GEN);
+ pcmd->params.rssi_info.action = wlan_cpu_to_le16(cmd_action);
+ pcmd->params.rssi_info.ndata = wlan_cpu_to_le16(pmpriv->data_avg_factor);
+ pcmd->params.rssi_info.nbcn = wlan_cpu_to_le16(pmpriv->bcn_avg_factor);
+
+ /* Reset SNR/NF/RSSI values in private structure */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_mac_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_MAC_CONTROL *pmac = &pcmd->params.mac_ctrl;
+ t_u16 action = *((t_u16 *) pdata_buf);
+
+ ENTER();
+
+ if (cmd_action != HostCmd_ACT_GEN_SET) {
+ PRINTM(MERROR, "wlan_cmd_mac_control(): support SET only.\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
+ pmac->action = wlan_cpu_to_le16(action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ t_u32 ul_temp;
+
+ ENTER();
+ PRINTM(MINFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(MAX_SNMP_BUF_SIZE);
+ cmd->size += MAX_SNMP_BUF_SIZE;
+ }
+
+ switch (cmd_oid) {
+ case DtimPeriod_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) DtimPeriod_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ ul_temp = *((t_u32 *) pdata_buf);
+ psnmp_mib->value[0] = (t_u8) ul_temp;
+ cmd->size += sizeof(t_u8);
+ }
+ break;
+ case FragThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) FragThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case RtsThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) RtsThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *(t_u16 *) (psnmp_mib->value) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+
+ case ShortRetryLim_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) ShortRetryLim_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = (*(t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11D_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Dot11D_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Dot11H_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case WwsMode_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) WwsMode_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Thermal_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Thermal_i);
+ break;
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ PRINTM(MINFO, "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
+ cmd_action, cmd_oid, wlan_le16_to_cpu(psnmp_mib->buf_size),
+ wlan_le16_to_cpu(*(t_u16 *) psnmp_mib->value));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of get_log.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_get_log(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND * cmd)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_power_cfg.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_tx_power_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &cmd->params.txp_cfg;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TXPWR_CFG));
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ ptxp = (HostCmd_DS_TXPWR_CFG *) pdata_buf;
+ if (ptxp->mode) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ memmove(pmpriv->adapter, ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t) + ppg_tlv->length);
+
+ ppg_tlv = (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg +
+ sizeof
+ (HostCmd_DS_TXPWR_CFG));
+ cmd->size +=
+ wlan_cpu_to_le16(sizeof(MrvlTypes_Power_Group_t) +
+ ppg_tlv->length);
+ ppg_tlv->type = wlan_cpu_to_le16(ppg_tlv->type);
+ ppg_tlv->length = wlan_cpu_to_le16(ppg_tlv->length);
+ } else {
+ memmove(pmpriv->adapter, ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ }
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ ptxp_cfg->cfg_index = wlan_cpu_to_le16(ptxp_cfg->cfg_index);
+ ptxp_cfg->mode = wlan_cpu_to_le32(ptxp_cfg->mode);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_tx_power.
+ *
+ * @param pmpriv A pointer to wlan_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
+ */
+static mlan_status
+wlan_cmd_802_11_rf_tx_power(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+
+ HostCmd_DS_802_11_RF_TX_POWER *prtp = &cmd->params.txp;
+
+ ENTER();
+
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RF_TX_POWER))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER);
+ prtp->action = cmd_action;
+
+ PRINTM(MINFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n",
+ cmd->size, cmd->command, prtp->action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_GET:
+ prtp->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ prtp->current_level = 0;
+ break;
+
+ case HostCmd_ACT_GEN_SET:
+ prtp->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ prtp->current_level = wlan_cpu_to_le16(*((t_u16 *) pdata_buf));
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN hs_config_param * pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &cmd->params.opt_hs_cfg;
+ t_u16 hs_activate = MFALSE;
+
+ ENTER();
+
+ if (pdata_buf == MNULL) {
+ /* New Activate command */
+ hs_activate = MTRUE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+
+ if (!hs_activate && (pdata_buf->conditions != HOST_SLEEP_CFG_CANCEL)
+ && ((pmadapter->arp_filter_size > 0)
+ && (pmadapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
+ PRINTM(MINFO, "Attach %d bytes ArpFilter to HSCfg cmd\n",
+ pmadapter->arp_filter_size);
+ memcpy(pmpriv->adapter,
+ ((t_u8 *) phs_cfg) + sizeof(HostCmd_DS_802_11_HS_CFG_ENH),
+ pmadapter->arp_filter, pmadapter->arp_filter_size);
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16(pmadapter->arp_filter_size +
+ sizeof(HostCmd_DS_802_11_HS_CFG_ENH) +
+ S_DS_GEN);
+ } else
+ cmd->size =
+ wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_HS_CFG_ENH));
+
+ if (hs_activate) {
+ phs_cfg->action = wlan_cpu_to_le16(HS_ACTIVATE);
+ phs_cfg->params.hs_activate.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
+ } else {
+ phs_cfg->action = wlan_cpu_to_le16(HS_CONFIGURE);
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->gap;
+ PRINTM(MCMND, "HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_address.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_mac_address(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.mac_addr.action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy(pmpriv->adapter, cmd->params.mac_addr.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+ // HEXDUMP("SET_CMD: MAC ADDRESS-", priv->CurrentAddr, 6);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_period.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_802_11_sleep_period(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_u16 * pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &cmd->params.sleep_pd;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) + S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sleep_pd->sleep_pd = wlan_cpu_to_le16(*(t_u16 *) pdata_buf);
+ }
+ pcmd_sleep_pd->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_params.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_802_11_sleep_params(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_u16 * pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *pcmd_sp = &cmd->params.sleep_param;
+ mlan_ds_sleep_params *psp = (mlan_ds_sleep_params *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PARAMS) + S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sp->reserved = (t_u16) psp->reserved;
+ pcmd_sp->error = (t_u16) psp->error;
+ pcmd_sp->offset = (t_u16) psp->offset;
+ pcmd_sp->stable_time = (t_u16) psp->stable_time;
+ pcmd_sp->cal_control = (t_u8) psp->cal_control;
+ pcmd_sp->external_sleep_clk = (t_u8) psp->ext_sleep_clk;
+
+ pcmd_sp->reserved = wlan_cpu_to_le16(pcmd_sp->reserved);
+ pcmd_sp->error = wlan_cpu_to_le16(pcmd_sp->error);
+ pcmd_sp->offset = wlan_cpu_to_le16(pcmd_sp->offset);
+ pcmd_sp->stable_time = wlan_cpu_to_le16(pcmd_sp->stable_time);
+ }
+ pcmd_sp->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_multicast_adr.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_mac_multicast_adr(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_multicast_list *pmcast_list = (mlan_multicast_list *) pdata_buf;
+ HostCmd_DS_MAC_MULTICAST_ADR *pmc_addr = &cmd->params.mc_addr;
+
+ ENTER();
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+ pmc_addr->action = wlan_cpu_to_le16(cmd_action);
+ pmc_addr->num_of_adrs =
+ wlan_cpu_to_le16((t_u16) pmcast_list->num_multicast_addr);
+ memcpy(pmpriv->adapter, pmc_addr->mac_list, pmcast_list->mac_list,
+ pmcast_list->num_multicast_addr * MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauthenticate.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_deauthenticate(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_DEAUTHENTICATE *pdeauth = &cmd->params.deauth;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) + S_DS_GEN);
+
+ /* Set AP MAC address */
+ memcpy(pmpriv->adapter, pdeauth->mac_addr, (t_u8 *) pdata_buf,
+ MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MCMND, "Deauth: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pdeauth->mac_addr[0], pdeauth->mac_addr[1], pdeauth->mac_addr[2],
+ pdeauth->mac_addr[3], pdeauth->mac_addr[4], pdeauth->mac_addr[5]);
+
+ if (pmpriv->adapter->state_11h.recvd_chanswann_event) {
+/** Reason code 36 = Requested from peer station as it is leaving the BSS */
+#define REASON_CODE_PEER_STA_LEAVING 36
+ pdeauth->reason_code = wlan_cpu_to_le16(REASON_CODE_PEER_STA_LEAVING);
+ } else {
+/** Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+ pdeauth->reason_code = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_stop.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_ad_hoc_stop(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN);
+
+ if (wlan_11h_is_active(pmpriv))
+ wlan_11h_activate(pmpriv, MNULL, MFALSE);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Length of WEP 40 bit key */
+#define WEP_40_BIT_LEN 5
+/** Length of WEP 104 bit key */
+#define WEP_104_BIT_LEN 13
+
+/**
+ * @brief This function sets WEP key(s) to key_param_set TLV(s).
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param key_param_set A pointer to MrvlIEtype_KeyParamSet_t structure
+ * @param key_param_len A pointer to the length variable
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_set_keyparamset_wep(mlan_private * priv,
+ MrvlIEtype_KeyParamSet_t * key_param_set,
+ t_u16 * key_param_len)
+{
+ int cur_key_param_len = 0;
+ t_u8 i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Multi-key_param_set TLV is supported */
+ for (i = 0; i < MRVL_NUM_WEP_KEY; i++) {
+ if ((priv->wep_key[i].key_length == WEP_40_BIT_LEN) ||
+ (priv->wep_key[i].key_length == WEP_104_BIT_LEN)) {
+ key_param_set->type = wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+/** Key_param_set WEP fixed length */
+#define KEYPARAMSET_WEP_FIXED_LEN 8
+ key_param_set->length =
+ wlan_cpu_to_le16((t_u16)
+ (priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN));
+ key_param_set->key_type_id = wlan_cpu_to_le16(KEY_TYPE_ID_WEP);
+ key_param_set->key_info = wlan_cpu_to_le16
+ (KEY_INFO_WEP_ENABLED | KEY_INFO_WEP_UNICAST |
+ KEY_INFO_WEP_MCAST);
+ key_param_set->key_len =
+ (t_u16) wlan_cpu_to_le16(priv->wep_key[i].key_length);
+ /* Set WEP key index */
+ key_param_set->key[0] = i;
+ /* Set default Tx key flag */
+ if (i == (priv->wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
+ key_param_set->key[1] = 1;
+ else
+ key_param_set->key[1] = 0;
+ memmove(priv->adapter, &key_param_set->key[2],
+ priv->wep_key[i].key_material, priv->wep_key[i].key_length);
+
+ cur_key_param_len = priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN + sizeof(MrvlIEtypesHeader_t);
+ *key_param_len += (t_u16) cur_key_param_len;
+ key_param_set =
+ (MrvlIEtype_KeyParamSet_t *) ((t_u8 *) key_param_set +
+ cur_key_param_len);
+ } else if (!priv->wep_key[i].key_length) {
+ continue;
+ } else {
+ PRINTM(MERROR, "key%d Length = %d is incorrect\n", (i + 1),
+ priv->wep_key[i].key_length);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of key_material.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material = &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *) pdata_buf;
+ t_u16 key_param_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ const t_u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN +
+ KEYPARAMSET_FIXED_LEN +
+ sizeof(MrvlIEtypesHeader_t));
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(KEYPARAMSET_FIXED_LEN);
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pkey_material->key_param_set.key_info |= KEY_INFO_MCAST_KEY;
+ else
+ pkey_material->key_param_set.key_info |= KEY_INFO_UCAST_KEY;
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ goto done;
+ }
+
+ if (!pkey) {
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ (MRVL_NUM_WEP_KEY * sizeof(MrvlIEtype_KeyParamSet_t)));
+ ret =
+ wlan_set_keyparamset_wep(pmpriv, &pkey_material->key_param_set,
+ &key_param_len);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ } else
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ if (pkey->is_wapi_key) {
+ PRINTM(MINFO, "Set WAPI Key\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_WAPI);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED));
+
+ pkey_material->key_param_set.key[0] = (t_u8) pkey->key_index;
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key[1] = 1;
+ else
+ pkey_material->key_param_set.key[1] = 0; /* set 0 when re-key */
+
+ if (0 != memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* WAPI
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_UNICAST);
+ else { /* WAPI group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_MCAST);
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ }
+
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(WAPI_KEY_LEN);
+ memcpy(pmpriv->adapter, &pkey_material->key_param_set.key[2],
+ pkey->key_material, pkey->key_len);
+ memcpy(pmpriv->adapter,
+ &pkey_material->key_param_set.key[2 + pkey->key_len], pkey->pn,
+ PN_SIZE);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ }
+ if (pkey->key_len == WPA_AES_KEY_LEN) {
+ PRINTM(MCMND, "WPA_AES\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+ if (pkey->key_index & MLAN_KEY_INDEX_UNICAST) /* AES pairwise key:
+ unicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+ else /* AES group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+ } else if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ PRINTM(MCMND, "WPA_TKIP\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+ if (pkey->key_index & MLAN_KEY_INDEX_UNICAST) /* TKIP pairwise key:
+ unicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+ else /* TKIP group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+ }
+
+ if (pkey_material->key_param_set.key_type_id) {
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len =
+ wlan_cpu_to_le16((t_u16) pkey->key_len);
+ memcpy(pmpriv->adapter, pkey_material->key_param_set.key,
+ pkey->key_material, pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16((t_u16) pkey->key_len + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (t_u16) (pkey->key_len + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of supplicant pmk
+ *
+ * @param pmpriv 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 or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_supplicant_pmk(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *ppassphrase_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ HostCmd_DS_802_11_SUPPLICANT_PMK *pesupplicant_psk =
+ &cmd->params.esupplicant_psk;
+ t_u8 *ptlv_buffer = (t_u8 *) pesupplicant_psk->tlv_buffer;
+ mlan_ds_passphrase *psk = (mlan_ds_passphrase *) pdata_buf;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+ /*
+ * Parse the rest of the buf here
+ * 1) <ssid="valid ssid"> - This will get the passphrase, AKMP
+ * for specified ssid, if none specified then it will get all.
+ * Eg: iwpriv <mlanX> passphrase 0:ssid=marvell
+ * 2) <psk="psk">:<passphrase="passphare">:<bssid="00:50:43:ef:23:f3">
+ * <ssid="valid ssid"> - passphrase and psk cannot be provided to
+ * the same SSID, Takes one SSID at a time, If ssid= is present
+ * the it should contain a passphrase or psk. If no arguments are
+ * provided then AKMP=802.1x, and passphrase should be provided
+ * after association.
+ * End of each parameter should be followed by a ':'(except for the
+ * last parameter) as the delimiter. If ':' has to be used in
+ * an SSID then a '/' should be preceded to ':' as a escape.
+ * Eg:iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl AP:psk=abcdefgh:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl/: AP:psk=abcdefgd:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase "1:ssid=mrvlAP:psk=abcdefgd"
+ * 3) <ssid="valid ssid"> - This will clear the passphrase
+ * for specified ssid, if none specified then it will clear all.
+ * Eg: iwpriv <mlanX> passphrase 2:ssid=marvell
+ */
+
+ /* -1 is for t_u8 TlvBuffer[1] as this should not be included */
+ cmd->size = sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1;
+ if (psk->ssid.ssid_len) {
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) ptlv_buffer;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len =
+ (t_u16) MIN(MLAN_MAX_SSID_LENGTH, psk->ssid.ssid_len);
+ memcpy(pmpriv->adapter, (char *) pssid_tlv->ssid, psk->ssid.ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, psk->ssid.ssid_len));
+ ptlv_buffer += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+ }
+ if (memcmp
+ (pmpriv->adapter, (t_u8 *) & psk->bssid, zero_mac, sizeof(zero_mac))) {
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *) ptlv_buffer;
+ pbssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_BSSID);
+ pbssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pmpriv->adapter, pbssid_tlv->bssid, (t_u8 *) & psk->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ ptlv_buffer += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pbssid_tlv->header.len = wlan_cpu_to_le16(pbssid_tlv->header.len);
+ }
+ if (psk->psk_type == MLAN_PSK_PASSPHRASE) {
+ ppassphrase_tlv = (MrvlIEtypes_Passphrase_t *) ptlv_buffer;
+ ppassphrase_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PASSPHRASE);
+ ppassphrase_tlv->header.len =
+ (t_u16) MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ psk->psk.passphrase.passphrase_len);
+ memcpy(pmpriv->adapter, ppassphrase_tlv->passphrase,
+ psk->psk.passphrase.passphrase, MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ psk->psk.passphrase.
+ passphrase_len));
+ ptlv_buffer +=
+ (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppassphrase_tlv->header.len =
+ wlan_cpu_to_le16(ppassphrase_tlv->header.len);
+ }
+ if (psk->psk_type == MLAN_PSK_PMK) {
+ ppmk_tlv = (MrvlIEtypes_PMK_t *) ptlv_buffer;
+ ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK);
+ ppmk_tlv->header.len = MLAN_MAX_KEY_LENGTH;
+ memcpy(pmpriv->adapter, ppmk_tlv->pmk, psk->psk.pmk.pmk,
+ MLAN_MAX_KEY_LENGTH);
+ ptlv_buffer += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len);
+ }
+ if ((cmd_action == HostCmd_ACT_GEN_SET) &&
+ ((pssid_tlv || pbssid_tlv) && (!ppmk_tlv && !ppassphrase_tlv))) {
+ PRINTM(MERROR,
+ "Invalid case,ssid/bssid present without pmk or passphrase\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PMK);
+ pesupplicant_psk->action = wlan_cpu_to_le16(cmd_action);
+ pesupplicant_psk->cache_result = 0;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant profile command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_supplicant_profile(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *sup_profile =
+ &cmd->params.esupplicant_profile;
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ t_u8 *ptlv_buffer = (t_u8 *) sup_profile->tlv_buf;
+ mlan_ds_esupp_mode *esupp = MNULL;
+
+ ENTER();
+
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SUPPLICANT_PROFILE) +
+ S_DS_GEN - 1);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PROFILE);
+ sup_profile->action = wlan_cpu_to_le16(cmd_action);
+ if ((cmd_action == HostCmd_ACT_GEN_SET) && pdata_buf) {
+ esupp = (mlan_ds_esupp_mode *) pdata_buf;
+ if (esupp->rsn_mode) {
+ encr_proto_tlv = (MrvlIEtypes_EncrProto_t *) ptlv_buffer;
+ encr_proto_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_ENCRYPTION_PROTO);
+ encr_proto_tlv->header.len =
+ (t_u16) sizeof(encr_proto_tlv->rsn_mode);
+ encr_proto_tlv->rsn_mode = wlan_cpu_to_le16(esupp->rsn_mode);
+ ptlv_buffer +=
+ (encr_proto_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (encr_proto_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ encr_proto_tlv->header.len =
+ wlan_cpu_to_le16(encr_proto_tlv->header.len);
+ }
+ if (esupp->act_paircipher || esupp->act_groupcipher) {
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *) ptlv_buffer;
+ pcipher_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CIPHER);
+ pcipher_tlv->header.len =
+ (t_u16) (sizeof(pcipher_tlv->pair_cipher) +
+ sizeof(pcipher_tlv->group_cipher));
+ if (esupp->act_paircipher) {
+ pcipher_tlv->pair_cipher =
+ wlan_cpu_to_le16(esupp->act_paircipher);
+ }
+ if (esupp->act_groupcipher) {
+ pcipher_tlv->group_cipher =
+ wlan_cpu_to_le16(esupp->act_groupcipher);
+ }
+ ptlv_buffer +=
+ (pcipher_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (pcipher_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pcipher_tlv->header.len = wlan_cpu_to_le16(pcipher_tlv->header.len);
+ }
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_channel.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_802_11_rf_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_chan = &cmd->params.rf_channel;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL)
+ + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->adhoc_start_band & BAND_A)
+ || (pmpriv->adapter->adhoc_start_band & BAND_AN)
+ )
+ prf_chan->rf_type = HostCmd_SCAN_RADIO_TYPE_A;
+ SET_SECONDARYCHAN(prf_chan->rf_type, pmpriv->adapter->chan_bandwidth);
+ prf_chan->rf_type = wlan_cpu_to_le16(prf_chan->rf_type);
+ prf_chan->current_channel = wlan_cpu_to_le16(*((t_u16 *) pdata_buf));
+ }
+ prf_chan->action = wlan_cpu_to_le16(cmd_action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ibss_coalescing_status.
+ *
+ * @param pmpriv 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 or MNULL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_ibss_coalescing_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal = &(cmd->params.ibss_coalescing);
+ t_u16 enable = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_STATUS) + S_DS_GEN);
+ cmd->result = 0;
+ pibss_coal->action = wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ if (pdata_buf != MNULL)
+ enable = *(t_u16 *) pdata_buf;
+ pibss_coal->enable = wlan_cpu_to_le16(enable);
+ break;
+
+ /* In other case.. Nothing to do */
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mgmt IE list.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_mgmt_ie_list(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ t_u16 req_len = 0, travel_len = 0;
+ custom_ie *cptr = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list = &(cmd->params.mgmt_ie_list);
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MGMT_IE_LIST);
+ cmd->size = sizeof(HostCmd_DS_MGMT_IE_LIST_CFG) + S_DS_GEN;
+ cmd->result = 0;
+ pmgmt_ie_list->action = wlan_cpu_to_le16(cmd_action);
+
+ cust_ie = (mlan_ds_misc_custom_ie *) pdata_buf;
+ pmgmt_ie_list->ds_mgmt_ie.type = wlan_cpu_to_le16(cust_ie->type);
+ pmgmt_ie_list->ds_mgmt_ie.len = wlan_cpu_to_le16(cust_ie->len);
+
+ if (pmgmt_ie_list->ds_mgmt_ie.ie_data_list && cust_ie->ie_data_list) {
+ req_len = cust_ie->len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (req_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) cust_ie->ie_data_list) + travel_len);
+ travel_len += cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -= cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask = wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ if (cust_ie->len)
+ memcpy(pmpriv->adapter, pmgmt_ie_list->ds_mgmt_ie.ie_data_list,
+ cust_ie->ie_data_list, cust_ie->len);
+ }
+
+ cmd->size -=
+ (MAX_MGMT_IE_INDEX_TO_FW * sizeof(custom_ie)) +
+ sizeof(tlvbuf_max_mgmt_ie);
+ cmd->size += cust_ie->len;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares system clock cfg command
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_sysclock_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *cfg = &cmd->params.sys_clock_cfg;
+ mlan_ds_misc_sys_clock *clk_cfg = (mlan_ds_misc_sys_clock *) pdata_buf;
+ int i = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG) + S_DS_GEN);
+
+ cfg->action = wlan_cpu_to_le16(cmd_action);
+ cfg->cur_sys_clk = wlan_cpu_to_le16(clk_cfg->cur_sys_clk);
+ cfg->sys_clk_type = wlan_cpu_to_le16(clk_cfg->sys_clk_type);
+ cfg->sys_clk_len = wlan_cpu_to_le16(clk_cfg->sys_clk_num) * sizeof(t_u16);
+ for (i = 0; i < clk_cfg->sys_clk_num; i++)
+ cfg->sys_clk[i] = wlan_cpu_to_le16(clk_cfg->sys_clk[i]);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reg_access.
+ *
+ * @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 or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_reg_access(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_reg_rw *reg_rw;
+
+ ENTER();
+
+ reg_rw = (mlan_ds_reg_rw *) pdata_buf;
+ switch (cmd->command) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ HostCmd_DS_MAC_REG_ACCESS *mac_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN);
+ mac_reg = (HostCmd_DS_MAC_REG_ACCESS *) & cmd->params.mac_reg;
+ mac_reg->action = wlan_cpu_to_le16(cmd_action);
+ mac_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ mac_reg->value = wlan_cpu_to_le32(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ HostCmd_DS_BBP_REG_ACCESS *bbp_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN);
+ bbp_reg = (HostCmd_DS_BBP_REG_ACCESS *) & cmd->params.bbp_reg;
+ bbp_reg->action = wlan_cpu_to_le16(cmd_action);
+ bbp_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ bbp_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *rf_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+ rf_reg = (HostCmd_DS_RF_REG_ACCESS *) & cmd->params.rf_reg;
+ rf_reg->action = wlan_cpu_to_le16(cmd_action);
+ rf_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ rf_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *cau_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+ cau_reg = (HostCmd_DS_RF_REG_ACCESS *) & cmd->params.rf_reg;
+ cau_reg->action = wlan_cpu_to_le16(cmd_action);
+ cau_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ cau_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ mlan_ds_read_eeprom *rd_eeprom = (mlan_ds_read_eeprom *) pdata_buf;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *) & cmd->params.eeprom;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) +
+ S_DS_GEN);
+ cmd_eeprom->action = wlan_cpu_to_le16(cmd_action);
+ cmd_eeprom->offset = wlan_cpu_to_le16(rd_eeprom->offset);
+ cmd_eeprom->byte_count = wlan_cpu_to_le16(rd_eeprom->byte_count);
+ cmd_eeprom->value = 0;
+ break;
+ }
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mem_access.
+ *
+ * @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
+ */
+static mlan_status
+wlan_cmd_mem_access(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_mem_rw *mem_rw = (mlan_ds_mem_rw *) pdata_buf;
+ HostCmd_DS_MEM_ACCESS *mem_access =
+ (HostCmd_DS_MEM_ACCESS *) & cmd->params.mem;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MEM_ACCESS) + S_DS_GEN);
+
+ mem_access->action = wlan_cpu_to_le16(cmd_action);
+ mem_access->addr = wlan_cpu_to_le32(mem_rw->addr);
+ mem_access->value = wlan_cpu_to_le32(mem_rw->value);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of subscribe event.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_subscribe_event(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_subscribe_evt *sub_evt = (mlan_ds_subscribe_evt *) pdata_buf;
+ HostCmd_DS_SUBSCRIBE_EVENT *evt =
+ (HostCmd_DS_SUBSCRIBE_EVENT *) & cmd->params.subscribe_event;
+ t_u16 cmd_size = 0;
+ t_u8 *tlv = MNULL;
+ MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_low = MNULL;
+ MrvlIEtypes_BeaconLowSnrThreshold_t *snr_low = MNULL;
+ MrvlIEtypes_FailureCount_t *fail_count = MNULL;
+ MrvlIEtypes_BeaconsMissed_t *beacon_missed = MNULL;
+ MrvlIEtypes_BeaconHighRssiThreshold_t *rssi_high = MNULL;
+ MrvlIEtypes_BeaconHighSnrThreshold_t *snr_high = MNULL;
+ MrvlIEtypes_DataLowRssiThreshold_t *data_rssi_low = MNULL;
+ MrvlIEtypes_DataLowSnrThreshold_t *data_snr_low = MNULL;
+ MrvlIEtypes_DataHighRssiThreshold_t *data_rssi_high = MNULL;
+ MrvlIEtypes_DataHighSnrThreshold_t *data_snr_high = MNULL;
+ MrvlIEtypes_LinkQualityThreshold_t *link_quality = MNULL;
+ MrvlIETypes_PreBeaconMissed_t *pre_bcn_missed = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT);
+ evt->action = wlan_cpu_to_le16(cmd_action);
+ cmd_size = sizeof(HostCmd_DS_SUBSCRIBE_EVENT) + S_DS_GEN;
+ if (cmd_action == HostCmd_ACT_GEN_GET)
+ goto done;
+#define HostCmd_ACT_BITWISE_SET 0x02
+ evt->action = wlan_cpu_to_le16(HostCmd_ACT_BITWISE_SET);
+ evt->event_bitmap = wlan_cpu_to_le16(sub_evt->evt_bitmap);
+ tlv = (t_u8 *) cmd + cmd_size;
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_RSSI_LOW) {
+ rssi_low = (MrvlIEtypes_BeaconLowRssiThreshold_t *) tlv;
+ rssi_low->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
+ rssi_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_low->value = sub_evt->low_rssi;
+ rssi_low->frequency = sub_evt->low_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_SNR_LOW) {
+ snr_low = (MrvlIEtypes_BeaconLowSnrThreshold_t *) tlv;
+ snr_low->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_low->value = sub_evt->low_snr;
+ snr_low->frequency = sub_evt->low_snr_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_MAX_FAIL) {
+ fail_count = (MrvlIEtypes_FailureCount_t *) tlv;
+ fail_count->header.type = wlan_cpu_to_le16(TLV_TYPE_FAILCOUNT);
+ fail_count->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_FailureCount_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ fail_count->value = sub_evt->failure_count;
+ fail_count->frequency = sub_evt->failure_count_freq;
+ tlv += sizeof(MrvlIEtypes_FailureCount_t);
+ cmd_size += sizeof(MrvlIEtypes_FailureCount_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_BEACON_MISSED) {
+ beacon_missed = (MrvlIEtypes_BeaconsMissed_t *) tlv;
+ beacon_missed->header.type = wlan_cpu_to_le16(TLV_TYPE_BCNMISS);
+ beacon_missed->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconsMissed_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ beacon_missed->value = sub_evt->beacon_miss;
+ beacon_missed->frequency = sub_evt->beacon_miss_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconsMissed_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconsMissed_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_RSSI_HIGH) {
+ rssi_high = (MrvlIEtypes_BeaconHighRssiThreshold_t *) tlv;
+ rssi_high->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+ rssi_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_high->value = sub_evt->high_rssi;
+ rssi_high->frequency = sub_evt->high_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_SNR_HIGH) {
+ snr_high = (MrvlIEtypes_BeaconHighSnrThreshold_t *) tlv;
+ snr_high->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_HIGH);
+ snr_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_high->value = sub_evt->high_snr;
+ snr_high->frequency = sub_evt->high_snr_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_RSSI_LOW) {
+ data_rssi_low = (MrvlIEtypes_DataLowRssiThreshold_t *) tlv;
+ data_rssi_low->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW_DATA);
+ data_rssi_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_rssi_low->value = sub_evt->data_low_rssi;
+ data_rssi_low->frequency = sub_evt->data_low_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_DataLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataLowRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_SNR_LOW) {
+ data_snr_low = (MrvlIEtypes_DataLowSnrThreshold_t *) tlv;
+ data_snr_low->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW_DATA);
+ data_snr_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_snr_low->value = sub_evt->data_low_snr;
+ data_snr_low->frequency = sub_evt->data_low_snr_freq;
+ tlv += sizeof(MrvlIEtypes_DataLowSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataLowSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_RSSI_HIGH) {
+ data_rssi_high = (MrvlIEtypes_DataHighRssiThreshold_t *) tlv;
+ data_rssi_high->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_HIGH_DATA);
+ data_rssi_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataHighRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_rssi_high->value = sub_evt->data_high_rssi;
+ data_rssi_high->frequency = sub_evt->data_high_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_DataHighRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataHighRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_SNR_HIGH) {
+ data_snr_high = (MrvlIEtypes_DataHighSnrThreshold_t *) tlv;
+ data_snr_high->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_HIGH_DATA);
+ data_snr_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataHighSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_snr_high->value = sub_evt->data_high_snr;
+ data_snr_high->frequency = sub_evt->data_high_snr_freq;
+ tlv += sizeof(MrvlIEtypes_DataHighSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataHighSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_LINK_QUALITY) {
+ link_quality = (MrvlIEtypes_LinkQualityThreshold_t *) tlv;
+ link_quality->header.type = wlan_cpu_to_le16(TLV_TYPE_LINK_QUALITY);
+ link_quality->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_LinkQualityThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ link_quality->link_snr = wlan_cpu_to_le16(sub_evt->link_snr);
+ link_quality->link_snr_freq = wlan_cpu_to_le16(sub_evt->link_snr_freq);
+ link_quality->link_rate = wlan_cpu_to_le16(sub_evt->link_rate);
+ link_quality->link_rate_freq =
+ wlan_cpu_to_le16(sub_evt->link_rate_freq);
+ link_quality->link_tx_latency =
+ wlan_cpu_to_le16(sub_evt->link_tx_latency);
+ link_quality->link_tx_lantency_freq =
+ wlan_cpu_to_le16(sub_evt->link_tx_lantency_freq);
+ tlv += sizeof(MrvlIEtypes_LinkQualityThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_LinkQualityThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_PRE_BEACON_LOST) {
+ pre_bcn_missed = (MrvlIETypes_PreBeaconMissed_t *) tlv;
+ pre_bcn_missed->header.type = wlan_cpu_to_le16(TLV_TYPE_PRE_BCNMISS);
+ pre_bcn_missed->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIETypes_PreBeaconMissed_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ pre_bcn_missed->value = sub_evt->pre_beacon_miss;
+ pre_bcn_missed->frequency = 0;
+ tlv += sizeof(MrvlIETypes_PreBeaconMissed_t);
+ cmd_size += sizeof(MrvlIETypes_PreBeaconMissed_t);
+ }
+ done:
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of OTP user data.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_cmd_otp_user_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_misc_otp_user_data *user_data =
+ (mlan_ds_misc_otp_user_data *) pdata_buf;
+ HostCmd_DS_OTP_USER_DATA *cmd_user_data =
+ (HostCmd_DS_OTP_USER_DATA *) & cmd->params.otp_user_data;
+ t_u16 cmd_size = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_OTP_READ_USER_DATA);
+ cmd_size = sizeof(HostCmd_DS_OTP_USER_DATA) + S_DS_GEN - 1;
+
+ cmd_user_data->action = wlan_cpu_to_le16(cmd_action);
+ cmd_user_data->reserved = 0;
+ cmd_user_data->user_data_length =
+ wlan_cpu_to_le16(user_data->user_data_length);
+ cmd_size += user_data->user_data_length;
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares inactivity timeout command
+ *
+ * @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
+ */
+static mlan_status
+wlan_cmd_inactivity_timeout(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ pmlan_ds_inactivity_to inac_to;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to = &cmd->params.inactivity_to;
+
+ ENTER();
+
+ inac_to = (mlan_ds_inactivity_to *) pdata_buf;
+
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_INACTIVITY_TIMEOUT_EXT) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+ cmd_inac_to->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cmd_inac_to->timeout_unit =
+ wlan_cpu_to_le16((t_u16) inac_to->timeout_unit);
+ cmd_inac_to->unicast_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->unicast_timeout);
+ cmd_inac_to->mcast_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->mcast_timeout);
+ cmd_inac_to->ps_entry_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_cmd_cfg_data(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_cmd_mac_control(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_cmd_802_11_mac_address(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret =
+ wlan_cmd_mac_multicast_adr(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret =
+ wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_cmd_tx_power_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_TX_POWER:
+ ret = wlan_cmd_802_11_rf_tx_power(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret =
+ wlan_cmd_enh_power_mode(pmpriv, cmd_ptr, cmd_action,
+ (t_u16) cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret =
+ wlan_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (hs_config_param *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_cmd_802_11_sleep_period(pmpriv, cmd_ptr,
+ cmd_action, (t_u16 *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_cmd_802_11_sleep_params(pmpriv, cmd_ptr,
+ cmd_action, (t_u16 *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_cmd_802_11_scan(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+ ret = wlan_cmd_bgscan_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_cmd_802_11_bg_scan_query(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_cmd_802_11_associate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = wlan_cmd_802_11_deauthenticate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ ret = wlan_cmd_802_11_ad_hoc_start(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_cmd_802_11_ad_hoc_join(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_cmd_802_11_ad_hoc_stop(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_cmd_802_11_get_log(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_cmd_802_11_rssi_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret =
+ wlan_cmd_802_11_snmp_mib(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret =
+ wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8) (*((t_u32 *) pdata_buf));
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.rx_mgmt_ind.action = wlan_cpu_to_le16(cmd_action);
+ cmd_ptr->params.rx_mgmt_ind.mgmt_subtype_mask =
+ wlan_cpu_to_le32((t_u32) (*((t_u32 *) pdata_buf)));
+ cmd_ptr->size = wlan_cpu_to_le16(sizeof(t_u32) + S_DS_GEN);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret =
+ wlan_cmd_802_11_rf_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status = WlanHardwareStatusInitializing;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_SOFT_RESET:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret =
+ wlan_cmd_802_11_key_material(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_cmd_802_11_supplicant_pmk(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_cmd_802_11_supplicant_profile(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_cmd_11n_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_cmd_tx_bf_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmd sent\n");
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_cmd_wmm_addts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_cmd_wmm_delts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_cmd_wmm_queue_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_cmd_wmm_queue_stats(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_cmd_wmm_ts_status(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret =
+ wlan_cmd_ibss_coalescing_status(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MGMT_IE_LIST:
+ ret = wlan_cmd_mgmt_ie_list(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = wlan_cmd_802_11_scan_ext(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_cmd_sysclock_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret = wlan_cmd_reg_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_cmd_mem_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_cmd_inactivity_timeout(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ ret = wlan_cmd_sdio_gpio_int(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pdata_buf) {
+ cmd_ptr->params.bss_mode.con_type = *(t_u8 *) pdata_buf;
+ } else
+#endif
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_ADHOC;
+ else if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_INFRA;
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SET_BSS_MODE) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret =
+ wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_cmd_wifi_direct_mode(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ ret = wlan_cmd_subscribe_event(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_OTP_READ_USER_DATA:
+ ret = wlan_cmd_otp_user_data(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_bss flag for first BSS
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_init_cmd(IN t_void * priv, IN t_u8 first_bss)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 enable = MTRUE;
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (first_bss == MTRUE) {
+ ret = wlan_adapter_init_cmd(pmpriv->adapter);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ }
+
+ /* get tx rate */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->data_rate = 0;
+
+ /* get tx power */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_TX_POWER,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* set ibss coalescing_status */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &enable);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, &amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
+ amsdu_aggr_ctrl.enable = MLAN_ACT_ENABLE;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ (t_void *) & amsdu_aggr_ctrl);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* MAC Control must be the last command in init_fw */
+ /* set MAC Control */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /** set last_init_cmd */
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_MAC_CONTROL;
+
+ if (first_bss == MFALSE) {
+ /* Get MAC address */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_802_11_MAC_ADDRESS;
+ }
+
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
new file mode 100644
index 000000000000..086d16ae5a62
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
@@ -0,0 +1,1726 @@
+/** @file mlan_sta_cmdresp.c
+ *
+ * @brief This file contains the handling of command
+ * responses generated by firmware.
+ *
+ * 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_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+#include "mlan_sdio.h"
+#include "mlan_meas.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+static void
+wlan_process_cmdresp_error(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &resp->params.psmode_enh;
+ PRINTM(MERROR,
+ "PS_MODE_ENH command failed: result=0x%x action=0x%X\n",
+ resp->result, wlan_le16_to_cpu(pm->action));
+ /*
+ * We do not re-try enter-ps command in ad-hoc mode.
+ */
+ if (wlan_le16_to_cpu(pm->action) == EN_AUTO_PS &&
+ (wlan_le16_to_cpu(pm->params.auto_ps.ps_bitmap) & BITMAP_STA_PS)
+ && pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ }
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ case HostCmd_CMD_802_11_SCAN:
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ break;
+
+ case HostCmd_CMD_MAC_CONTROL:
+ break;
+
+ default:
+ break;
+ }
+ /*
+ * Handling errors here
+ */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of RSSI info
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_rssi_info(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RSSI_INFO_RSP *prssi_info_rsp =
+ &resp->params.rssi_info_rsp;
+ mlan_ds_get_info *pget_info = MNULL;
+
+ ENTER();
+
+ pmpriv->data_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_last);
+ pmpriv->data_nf_last = wlan_le16_to_cpu(prssi_info_rsp->data_nf_last);
+
+ pmpriv->data_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_avg);
+ pmpriv->data_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->data_nf_avg);
+
+ pmpriv->bcn_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_last);
+ pmpriv->bcn_nf_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_last);
+
+ pmpriv->bcn_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_avg);
+ pmpriv->bcn_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_avg);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_buf != MNULL) {
+ pget_info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+
+ memset(pmpriv->adapter, &pget_info->param.signal, 0,
+ sizeof(mlan_ds_get_signal));
+
+ pget_info->param.signal.selector = ALL_RSSI_INFO_MASK;
+
+ /* RSSI */
+ pget_info->param.signal.bcn_rssi_last = pmpriv->bcn_rssi_last;
+ pget_info->param.signal.bcn_rssi_avg = pmpriv->bcn_rssi_avg;
+ pget_info->param.signal.data_rssi_last = pmpriv->data_rssi_last;
+ pget_info->param.signal.data_rssi_avg = pmpriv->data_rssi_avg;
+
+ /* SNR */
+ pget_info->param.signal.bcn_snr_last =
+ CAL_SNR(pmpriv->bcn_rssi_last, pmpriv->bcn_nf_last);
+ pget_info->param.signal.bcn_snr_avg =
+ CAL_SNR(pmpriv->bcn_rssi_avg, pmpriv->bcn_nf_avg);
+ pget_info->param.signal.data_snr_last =
+ CAL_SNR(pmpriv->data_rssi_last, pmpriv->data_nf_last);
+ pget_info->param.signal.data_snr_avg =
+ CAL_SNR(pmpriv->data_rssi_avg, pmpriv->data_nf_avg);
+
+ /* NF */
+ pget_info->param.signal.bcn_nf_last = pmpriv->bcn_nf_last;
+ pget_info->param.signal.bcn_nf_avg = pmpriv->bcn_nf_avg;
+ pget_info->param.signal.data_nf_last = pmpriv->data_nf_last;
+ pget_info->param.signal.data_nf_avg = pmpriv->data_nf_avg;
+
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_control
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_mac_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psmib = &resp->params.smib;
+ t_u16 oid = wlan_le16_to_cpu(psmib->oid);
+ t_u16 query_type = wlan_le16_to_cpu(psmib->query_type);
+ t_u32 ul_temp;
+ mlan_ds_snmp_mib *mib = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf)
+ mib = (mlan_ds_snmp_mib *) pioctl_buf->pbuf;
+
+ PRINTM(MINFO, "SNMP_RESP: value of the oid = 0x%x, query_type=0x%x\n", oid,
+ query_type);
+ PRINTM(MINFO, "SNMP_RESP: Buf size = 0x%x\n",
+ wlan_le16_to_cpu(psmib->buf_size));
+ if (query_type == HostCmd_ACT_GEN_GET) {
+ switch (oid) {
+ case DtimPeriod_i:
+ ul_temp = psmib->value[0];
+ PRINTM(MINFO, "SNMP_RESP: DTIM Period =%u\n", ul_temp);
+ if (mib)
+ mib->param.dtim_period = ul_temp;
+ break;
+ case FragThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: FragThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.frag_threshold = ul_temp;
+ break;
+
+ case RtsThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.rts_threshold = ul_temp;
+ break;
+
+ case ShortRetryLim_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ if (mib)
+ mib->param.retry_count = ul_temp;
+ break;
+ case WwsMode_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: WWSCfg =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *) pioctl_buf->pbuf)->param.wws_cfg =
+ ul_temp;
+ break;
+ case Thermal_i:
+ ul_temp = wlan_le32_to_cpu(*((t_u32 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: Thermal =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *) pioctl_buf->pbuf)->param.thermal =
+ ul_temp;
+ break;
+
+ default:
+ break;
+ }
+ } else { /* (query_type == HostCmd_ACT_GEN_SET) */
+ /* Update state for 11d */
+ if (oid == Dot11D_i) {
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ /* Set 11d state to private */
+ pmpriv->state_11d.enable_11d = ul_temp;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ pmpriv->state_11d.user_enable_11d = ul_temp;
+ }
+ /* Update state for 11h */
+ if (oid == Dot11H_i) {
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ /* Set 11h state to priv */
+ pmpriv->intf_state_11h.is_11h_active = (ul_temp & ENABLE_11H_MASK);
+ /* Set radar_det state to adapter */
+ pmpriv->adapter->state_11h.is_master_radar_det_active
+ = (ul_temp & MASTER_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ pmpriv->adapter->state_11h.is_slave_radar_det_active
+ = (ul_temp & SLAVE_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ }
+ }
+
+ if (pioctl_buf) {
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_snmp_mib);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of get_log
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_get_log(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_GET_LOG *pget_log =
+ (HostCmd_DS_802_11_GET_LOG *) & resp->params.get_log;
+ mlan_ds_get_info *pget_info = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ pget_info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ pget_info->param.stats.mcast_tx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_tx_frame);
+ pget_info->param.stats.failed = wlan_le32_to_cpu(pget_log->failed);
+ pget_info->param.stats.retry = wlan_le32_to_cpu(pget_log->retry);
+ pget_info->param.stats.multi_retry =
+ wlan_le32_to_cpu(pget_log->multiretry);
+ pget_info->param.stats.frame_dup =
+ wlan_le32_to_cpu(pget_log->frame_dup);
+ pget_info->param.stats.rts_success =
+ wlan_le32_to_cpu(pget_log->rts_success);
+ pget_info->param.stats.rts_failure =
+ wlan_le32_to_cpu(pget_log->rts_failure);
+ pget_info->param.stats.ack_failure =
+ wlan_le32_to_cpu(pget_log->ack_failure);
+ pget_info->param.stats.rx_frag = wlan_le32_to_cpu(pget_log->rx_frag);
+ pget_info->param.stats.mcast_rx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_rx_frame);
+ pget_info->param.stats.fcs_error =
+ wlan_le32_to_cpu(pget_log->fcs_error);
+ pget_info->param.stats.tx_frame = wlan_le32_to_cpu(pget_log->tx_frame);
+ pget_info->param.stats.wep_icv_error[0] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[0]);
+ pget_info->param.stats.wep_icv_error[1] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[1]);
+ pget_info->param.stats.wep_icv_error[2] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[2]);
+ pget_info->param.stats.wep_icv_error[3] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[3]);
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get power level and rate index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdata_buf Pointer to the data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_power_level(pmlan_private pmpriv, void *pdata_buf)
+{
+ int length = -1, max_power = -1, min_power = -1;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+
+ ENTER();
+
+ if (pdata_buf) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+ length = ppg_tlv->length;
+ if (length > 0) {
+ max_power = pg->power_max;
+ min_power = pg->power_min;
+ length -= sizeof(Power_Group_t);
+ }
+ while (length) {
+ pg++;
+ if (max_power < pg->power_max) {
+ max_power = pg->power_max;
+ }
+ if (min_power > pg->power_min) {
+ min_power = pg->power_min;
+ }
+ length -= sizeof(Power_Group_t);
+ }
+ if (ppg_tlv->length > 0) {
+ pmpriv->min_tx_power_level = (t_u8) min_power;
+ pmpriv->max_tx_power_level = (t_u8) max_power;
+ }
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_power_cfg
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_tx_power_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &resp->params.txp_cfg;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ t_u16 action = wlan_le16_to_cpu(ptxp_cfg->action);
+ mlan_ds_power_cfg *power = MNULL;
+ t_u32 data[5];
+
+ ENTER();
+
+ ppg_tlv = (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg
+ + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv + sizeof(MrvlTypes_Power_Group_t));
+
+ switch (action) {
+ case HostCmd_ACT_GEN_GET:
+ ppg_tlv->length = wlan_le16_to_cpu(ppg_tlv->length);
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusInitializing)
+ wlan_get_power_level(pmpriv, ptxp_cfg);
+ pmpriv->tx_power_level = (t_u16) pg->power_min;
+ break;
+
+ case HostCmd_ACT_GEN_SET:
+ if (wlan_le32_to_cpu(ptxp_cfg->mode)) {
+ if (pg->power_max == pg->power_min)
+ pmpriv->tx_power_level = (t_u16) pg->power_min;
+ }
+ break;
+
+ default:
+ PRINTM(MERROR, "CMD_RESP: unknown command action %d\n", action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level,
+ pmpriv->max_tx_power_level, pmpriv->min_tx_power_level);
+
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *) pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written
+ = sizeof(mlan_power_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level = pmpriv->tx_power_level;
+ if (wlan_le32_to_cpu(ptxp_cfg->mode))
+ power->param.power_cfg.is_power_auto = 0;
+ else
+ power->param.power_cfg.is_power_auto = 1;
+ } else {
+ power->param.power_ext.len = 0;
+ while (ppg_tlv->length) {
+ data[0] = pg->first_rate_code;
+ data[1] = pg->last_rate_code;
+ if (pg->modulation_class == MOD_CLASS_OFDM) {
+ data[0] += MLAN_RATE_INDEX_OFDM0;
+ data[1] += MLAN_RATE_INDEX_OFDM0;
+ } else if (pg->modulation_class == MOD_CLASS_HT) {
+ data[0] += MLAN_RATE_INDEX_MCS0;
+ data[1] += MLAN_RATE_INDEX_MCS0;
+ if (pg->ht_bandwidth == HT_BW_40) {
+ data[0] |= TX_RATE_HT_BW40_BIT;
+ data[1] |= TX_RATE_HT_BW40_BIT;
+ }
+ }
+ data[2] = pg->power_min;
+ data[3] = pg->power_max;
+ data[4] = pg->power_step;
+ memcpy(pmpriv->adapter,
+ (t_u8 *) (&power->param.power_ext.
+ power_data[power->param.power_ext.len]),
+ (t_u8 *) data, sizeof(data));
+ power->param.power_ext.len += 5;
+ pg++;
+ ppg_tlv->length -= sizeof(Power_Group_t);
+ }
+ pioctl_buf->data_read_written
+ = sizeof(mlan_power_cfg_ext) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_tx_power
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_rf_tx_power(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp;
+ t_u16 action = wlan_le16_to_cpu(rtp->action);
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ pmpriv->tx_power_level = wlan_le16_to_cpu(rtp->current_level);
+
+ if (action == HostCmd_ACT_GEN_GET) {
+ pmpriv->max_tx_power_level = rtp->max_power;
+ pmpriv->min_tx_power_level = rtp->min_power;
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *) pioctl_buf->pbuf;
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written
+ = sizeof(mlan_power_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level = pmpriv->tx_power_level;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level,
+ pmpriv->max_tx_power_level, pmpriv->min_tx_power_level);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_period
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_sleep_period(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &resp->params.sleep_pd;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 sleep_pd = 0;
+
+ ENTER();
+
+ sleep_pd = wlan_le16_to_cpu(pcmd_sleep_pd->sleep_pd);
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ pm_cfg->param.sleep_period = (t_u32) sleep_pd;
+ pioctl_buf->data_read_written = sizeof(pm_cfg->param.sleep_period)
+ + MLAN_SUB_COMMAND_SIZE;
+ }
+ pmpriv->adapter->sleep_period.period = sleep_pd;
+
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ if ((pmpriv->adapter->sleep_period.period != 0) &&
+ (pmpriv->adapter->sleep_period.period != SLEEP_PERIOD_RESERVED_FF)) {
+ pmpriv->adapter->gen_null_pkt = MTRUE;
+ } else {
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+ pmpriv->adapter->gen_null_pkt = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_params
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_sleep_params(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *presp_sp = &resp->params.sleep_param;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ mlan_ds_sleep_params *psp = MNULL;
+ sleep_params_t *psleep_params = &pmpriv->adapter->sleep_params;
+
+ ENTER();
+
+ psleep_params->sp_reserved = wlan_le16_to_cpu(presp_sp->reserved);
+ psleep_params->sp_error = wlan_le16_to_cpu(presp_sp->error);
+ psleep_params->sp_offset = wlan_le16_to_cpu(presp_sp->offset);
+ psleep_params->sp_stable_time = wlan_le16_to_cpu(presp_sp->stable_time);
+ psleep_params->sp_cal_control = presp_sp->cal_control;
+ psleep_params->sp_ext_sleep_clk = presp_sp->external_sleep_clk;
+
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ psp = (mlan_ds_sleep_params *) & pm_cfg->param.sleep_params;
+
+ psp->error = (t_u32) psleep_params->sp_error;
+ psp->offset = (t_u32) psleep_params->sp_offset;
+ psp->stable_time = (t_u32) psleep_params->sp_stable_time;
+ psp->cal_control = (t_u32) psleep_params->sp_cal_control;
+ psp->ext_sleep_clk = (t_u32) psleep_params->sp_ext_sleep_clk;
+ psp->reserved = (t_u32) psleep_params->sp_reserved;
+
+ pioctl_buf->data_read_written = sizeof(pm_cfg->param.sleep_params)
+ + MLAN_SUB_COMMAND_SIZE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_address
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_mac_address(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_MAC_ADDRESS *pmac_addr = &resp->params.mac_addr;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ memcpy(pmpriv->adapter, pmpriv->curr_addr, pmac_addr->mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MINFO, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmpriv->curr_addr[0], pmpriv->curr_addr[1], pmpriv->curr_addr[2],
+ pmpriv->curr_addr[3], pmpriv->curr_addr[4], pmpriv->curr_addr[5]);
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ memcpy(pmpriv->adapter, &bss->param.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pioctl_buf->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of multicast_address
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_mac_multicast_adr(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+ if (pioctl_buf) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of deauthenticate
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_deauthenticate(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+
+ pmadapter->dbg.num_cmd_deauth++;
+
+ if (!memcmp(pmadapter, resp->params.deauth.mac_addr,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(resp->params.deauth.mac_addr))) {
+ wlan_reset_connect_state(pmpriv, MTRUE);
+
+ }
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_stop
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_ad_hoc_stop(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of key_material
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey = &resp->params.key_material;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pkey->action) == HostCmd_ACT_GEN_SET) {
+ if ((wlan_le16_to_cpu(pkey->key_param_set.key_info) &
+ KEY_INFO_TKIP_MCAST)) {
+ PRINTM(MINFO, "key: GTK is set\n");
+ pmpriv->wpa_is_gtk_set = MTRUE;
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ /* GTK is set, open the port */
+ PRINTM(MINFO, "GTK_SET: Open port for WPA/WPA2 h-supp mode\n");
+ pmpriv->port_open = MTRUE;
+ }
+ pmpriv->scan_block = MFALSE;
+ }
+ } else {
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(pkey->key_param_set.type) ==
+ TLV_TYPE_KEY_MATERIAL)) {
+ PRINTM(MIOCTL, "key_type_id=%d, key_len=%d, key_info=0x%x\n",
+ wlan_le16_to_cpu(pkey->key_param_set.key_type_id),
+ wlan_le16_to_cpu(pkey->key_param_set.key_len),
+ wlan_le16_to_cpu(pkey->key_param_set.key_info));
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+#define WAPI_KEY_SIZE 32
+ switch (wlan_le16_to_cpu(pkey->key_param_set.key_type_id)) {
+ case KEY_TYPE_ID_WEP:
+ sec->param.encrypt_key.key_index = pkey->key_param_set.key[0];
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ &pkey->key_param_set.key[2],
+ sec->param.encrypt_key.key_len);
+ break;
+ case KEY_TYPE_ID_TKIP:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key, sec->param.encrypt_key.key_len);
+ break;
+ case KEY_TYPE_ID_AES:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key, sec->param.encrypt_key.key_len);
+ break;
+ case KEY_TYPE_ID_WAPI:
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_index = pkey->key_param_set.key[0];
+ sec->param.encrypt_key.key_len = WAPI_KEY_SIZE;
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ &pkey->key_param_set.key[2],
+ sec->param.encrypt_key.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.pn,
+ &pkey->key_param_set.key[2 + WAPI_KEY_SIZE], PN_SIZE);
+ break;
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant pmk response
+ *
+ * @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_FAILURE
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_pmk(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PMK *supplicant_pmk_resp =
+ &resp->params.esupplicant_psk;
+ mlan_ds_sec_cfg sec_buf;
+ mlan_ds_sec_cfg *sec = MNULL;
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *passphrase_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ t_u8 *tlv_buf = (t_u8 *) supplicant_pmk_resp->tlv_buffer;
+ t_u16 action = wlan_le16_to_cpu(supplicant_pmk_resp->action);
+ int tlv_buf_len = 0;
+ t_u16 tlv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ tlv_buf_len = resp->size - (sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) +
+ S_DS_GEN - 1);
+ if (pioctl_buf) {
+ if (((mlan_ds_bss *) pioctl_buf->pbuf)->sub_command ==
+ MLAN_OID_BSS_FIND_BSS)
+ sec = &sec_buf;
+ else
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ while (tlv_buf_len > 0) {
+ tlv = (*tlv_buf) | (*(tlv_buf + 1) << 8);
+ if ((tlv != TLV_TYPE_SSID) && (tlv != TLV_TYPE_BSSID) &&
+ (tlv != TLV_TYPE_PASSPHRASE)
+ && (tlv != TLV_TYPE_PMK))
+ break;
+ switch (tlv) {
+ case TLV_TYPE_SSID:
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) tlv_buf;
+ pssid_tlv->header.len =
+ wlan_le16_to_cpu(pssid_tlv->header.len);
+ memcpy(pmpriv->adapter, sec->param.passphrase.ssid.ssid,
+ pssid_tlv->ssid, MIN(MLAN_MAX_SSID_LENGTH,
+ pssid_tlv->header.len));
+ sec->param.passphrase.ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, pssid_tlv->header.len);
+ tlv_buf +=
+ pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_BSSID:
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *) tlv_buf;
+ pbssid_tlv->header.len =
+ wlan_le16_to_cpu(pbssid_tlv->header.len);
+ memcpy(pmpriv->adapter, &sec->param.passphrase.bssid,
+ pbssid_tlv->bssid, MLAN_MAC_ADDR_LENGTH);
+ tlv_buf +=
+ pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PASSPHRASE:
+ passphrase_tlv = (MrvlIEtypes_Passphrase_t *) tlv_buf;
+ passphrase_tlv->header.len =
+ wlan_le16_to_cpu(passphrase_tlv->header.len);
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ sec->param.passphrase.psk.passphrase.passphrase_len =
+ passphrase_tlv->header.len;
+ memcpy(pmpriv->adapter,
+ sec->param.passphrase.psk.passphrase.passphrase,
+ passphrase_tlv->passphrase,
+ MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ passphrase_tlv->header.len));
+ tlv_buf +=
+ passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PMK:
+ ppmk_tlv = (MrvlIEtypes_PMK_t *) tlv_buf;
+ ppmk_tlv->header.len =
+ wlan_le16_to_cpu(ppmk_tlv->header.len);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ memcpy(pmpriv->adapter, sec->param.passphrase.psk.pmk.pmk,
+ ppmk_tlv->pmk, MIN(MLAN_MAX_KEY_LENGTH,
+ ppmk_tlv->header.len));
+ tlv_buf +=
+ ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+
+ }
+ }
+ if (((mlan_ds_bss *) pioctl_buf->pbuf)->sub_command ==
+ MLAN_OID_BSS_FIND_BSS) {
+ wlan_set_ewpa_mode(pmpriv, &sec->param.passphrase);
+ ret = wlan_find_bss(pmpriv, pioctl_buf);
+ }
+ } else if (action == HostCmd_ACT_GEN_SET) {
+ PRINTM(MINFO, "Esupp PMK set: enable ewpa query\n");
+ pmpriv->ewpa_query = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the supplicant profile response
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_profile(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *psup_profile =
+ &resp->params.esupplicant_profile;
+ MrvlIEtypesHeader_t *head;
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 *tlv;
+ int len;
+
+ ENTER();
+
+ len = resp->size - S_DS_GEN - sizeof(t_u16);
+ tlv = psup_profile->tlv_buf;
+ if (pioctl_buf) {
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+ while (len > 0) {
+ head = (MrvlIEtypesHeader_t *) tlv;
+ head->type = wlan_le16_to_cpu(head->type);
+ head->len = wlan_le16_to_cpu(head->len);
+ switch (head->type) {
+ case TLV_TYPE_ENCRYPTION_PROTO:
+ encr_proto_tlv = (MrvlIEtypes_EncrProto_t *) head;
+ sec->param.esupp_mode.rsn_mode =
+ wlan_le16_to_cpu(encr_proto_tlv->rsn_mode);
+ PRINTM(MINFO, "rsn_mode=0x%x\n",
+ sec->param.esupp_mode.rsn_mode);
+ break;
+ case TLV_TYPE_CIPHER:
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *) head;
+ sec->param.esupp_mode.act_paircipher = pcipher_tlv->pair_cipher;
+ sec->param.esupp_mode.act_groupcipher =
+ pcipher_tlv->group_cipher;
+ PRINTM(MINFO, "paircipher=0x%x, groupcipher=0x%x\n",
+ sec->param.esupp_mode.act_paircipher,
+ sec->param.esupp_mode.act_groupcipher);
+ break;
+ }
+ len -= (head->len - sizeof(MrvlIEtypesHeader_t));
+ tlv = tlv + (head->len + sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_channel
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_802_11_rf_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_channel = &resp->params.rf_channel;
+ t_u16 new_channel = wlan_le16_to_cpu(prf_channel->current_channel);
+ mlan_ds_bss *bss = MNULL;
+ ENTER();
+ if (pmpriv->curr_bss_params.bss_descriptor.channel != new_channel) {
+ PRINTM(MINFO, "Channel Switch: %d to %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel, new_channel);
+ /* Update the channel again */
+ pmpriv->curr_bss_params.bss_descriptor.channel = new_channel;
+ }
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ bss->param.bss_chan.channel = new_channel;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the ibss_coalescing_status resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_ibss_coalescing_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal_resp =
+ &(resp->params.ibss_coalescing);
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pibss_coal_resp->action) == HostCmd_ACT_GEN_SET) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "New BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pibss_coal_resp->bssid[0], pibss_coal_resp->bssid[1],
+ pibss_coal_resp->bssid[2], pibss_coal_resp->bssid[3],
+ pibss_coal_resp->bssid[4], pibss_coal_resp->bssid[5]);
+
+ /* If rsp has MNULL BSSID, Just return..... No Action */
+ if (!memcmp
+ (pmpriv->adapter, pibss_coal_resp->bssid, zero_mac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MMSG, "New BSSID is MNULL\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* If BSSID is diff, modify current BSS parameters */
+ if (memcmp
+ (pmpriv->adapter, pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH)) {
+ /* BSSID */
+ memcpy(pmpriv->adapter,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH);
+
+ /* Beacon Interval and ATIM window */
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period
+ = wlan_le16_to_cpu(pibss_coal_resp->beacon_interval);
+ pmpriv->curr_bss_params.bss_descriptor.atim_window
+ = wlan_le16_to_cpu(pibss_coal_resp->atim_window);
+
+ /* ERP Information */
+ pmpriv->curr_bss_params.bss_descriptor.erp_flags
+ = (t_u8) wlan_le16_to_cpu(pibss_coal_resp->use_g_rate_protect);
+
+ pmpriv->adhoc_state = ADHOC_COALESCED;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of MGMT_IE_LIST
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_mgmt_ie_list(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ t_u16 resp_len = 0, travel_len = 0;
+ int i = 0;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ custom_ie *cptr;
+ tlvbuf_max_mgmt_ie *max_mgmt_ie = MNULL;
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list = &(resp->params.mgmt_ie_list);
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pmgmt_ie_list->action) == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->state_rdh.stage == RDH_SET_CUSTOM_IE) ||
+ (pmpriv->adapter->state_rdh.stage == RDH_REM_CUSTOM_IE))
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ cust_ie = (mlan_ds_misc_custom_ie *) & pmgmt_ie_list->ds_mgmt_ie;
+ max_mgmt_ie =
+ (tlvbuf_max_mgmt_ie *) ((t_u8 *) cust_ie + cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t));
+ if (cust_ie) {
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len = wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) cust_ie->ie_data_list) + travel_len);
+ cptr->ie_index = wlan_le16_to_cpu(cptr->ie_index);
+ cptr->mgmt_subtype_mask = wlan_le16_to_cpu(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(cptr->ie_length);
+ travel_len += cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ resp_len -= cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ }
+ memcpy(pmpriv->adapter, &misc->param.cust_ie, cust_ie,
+ (cust_ie->len + sizeof(MrvlIEtypesHeader_t)));
+ if (max_mgmt_ie) {
+ max_mgmt_ie->type = wlan_le16_to_cpu(max_mgmt_ie->type);
+ if (max_mgmt_ie->type == TLV_TYPE_MAX_MGMT_IE) {
+ max_mgmt_ie->len = wlan_le16_to_cpu(max_mgmt_ie->len);
+ max_mgmt_ie->count = wlan_le16_to_cpu(max_mgmt_ie->count);
+ for (i = 0; i < max_mgmt_ie->count; i++) {
+ max_mgmt_ie->info[i].buf_size =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].buf_size);
+ max_mgmt_ie->info[i].buf_count =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].buf_count);
+ }
+ /* Append max_mgmt_ie TLV after custom_ie */
+ memcpy(pmpriv->adapter,
+ (t_u8 *) & misc->param.cust_ie + (cust_ie->len +
+ sizeof
+ (MrvlIEtypesHeader_t)),
+ max_mgmt_ie,
+ max_mgmt_ie->len + sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sysclock
+ *
+ * @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
+ */
+static mlan_status
+wlan_ret_sysclock_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *mis_ccfg = MNULL;
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *clk_cfg = &resp->params.sys_clock_cfg;
+ int i = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ mis_ccfg = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ mis_ccfg->param.sys_clock.cur_sys_clk =
+ wlan_le16_to_cpu(clk_cfg->cur_sys_clk);
+ mis_ccfg->param.sys_clock.sys_clk_type =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_type);
+ mis_ccfg->param.sys_clock.sys_clk_num =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_len) / sizeof(t_u16);
+ for (i = 0; i < mis_ccfg->param.sys_clock.sys_clk_num; i++)
+ mis_ccfg->param.sys_clock.sys_clk[i] =
+ wlan_le16_to_cpu(clk_cfg->sys_clk[i]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of reg_access
+ *
+ * @param type The type of reg access (MAC, BBP or RF)
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_reg_access(mlan_adapter * pmadapter,
+ t_u16 type,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_reg_rw *reg_rw = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *) pioctl_buf->pbuf;
+ reg_rw = &reg_mem->param.reg_rw;
+ switch (type) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ HostCmd_DS_MAC_REG_ACCESS *reg;
+ reg = (HostCmd_DS_MAC_REG_ACCESS *) & resp->params.mac_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = wlan_le32_to_cpu(reg->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ HostCmd_DS_BBP_REG_ACCESS *reg;
+ reg = (HostCmd_DS_BBP_REG_ACCESS *) & resp->params.bbp_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rf_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rf_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ mlan_ds_read_eeprom *eeprom = &reg_mem->param.rd_eeprom;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *) & resp->params.eeprom;
+ cmd_eeprom->byte_count =
+ wlan_le16_to_cpu(cmd_eeprom->byte_count);
+ PRINTM(MINFO, "EEPROM read len=%x\n", cmd_eeprom->byte_count);
+ if (eeprom->byte_count < cmd_eeprom->byte_count) {
+ eeprom->byte_count = 0;
+ PRINTM(MINFO, "EEPROM read return length is too big\n");
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ eeprom->offset = wlan_le16_to_cpu(cmd_eeprom->offset);
+ eeprom->byte_count = cmd_eeprom->byte_count;
+ if (eeprom->byte_count > 0) {
+ memcpy(pmadapter, &eeprom->value, &cmd_eeprom->value,
+ MIN(MAX_EEPROM_DATA, eeprom->byte_count));
+ HEXDUMP("EEPROM", (char *) &eeprom->value,
+ MIN(MAX_EEPROM_DATA, eeprom->byte_count));
+ }
+ break;
+ }
+ default:
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mem_access
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mem_access(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_mem_rw *mem_rw = MNULL;
+ HostCmd_DS_MEM_ACCESS *mem = (HostCmd_DS_MEM_ACCESS *) & resp->params.mem;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *) pioctl_buf->pbuf;
+ mem_rw = &reg_mem->param.mem_rw;
+
+ mem_rw->addr = wlan_le32_to_cpu(mem->addr);
+ mem_rw->value = wlan_le32_to_cpu(mem->value);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of inactivity timeout
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_inactivity_timeout(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_ds_inactivity_to *inac_to = MNULL;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to =
+ (HostCmd_DS_INACTIVITY_TIMEOUT_EXT *) & resp->params.inactivity_to;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pmcfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ inac_to->timeout_unit = wlan_le16_to_cpu(cmd_inac_to->timeout_unit);
+ inac_to->unicast_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->unicast_timeout);
+ inac_to->mcast_timeout = wlan_le16_to_cpu(cmd_inac_to->mcast_timeout);
+ inac_to->ps_entry_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * subscribe event
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_subscribe_event(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+
+ HostCmd_DS_SUBSCRIBE_EVENT *evt =
+ (HostCmd_DS_SUBSCRIBE_EVENT *) & resp->params.subscribe_event;
+ mlan_ds_subscribe_evt *sub_evt = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ sub_evt = &misc->param.subscribe_event;
+ sub_evt->evt_bitmap = wlan_le16_to_cpu(evt->event_bitmap);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_misc_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * OTP user data
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_otp_user_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+
+ HostCmd_DS_OTP_USER_DATA *cmd_user_data =
+ (HostCmd_DS_OTP_USER_DATA *) & resp->params.otp_user_data;
+ mlan_ds_misc_otp_user_data *user_data = MNULL;
+
+ ENTER();
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ user_data = (mlan_ds_misc_otp_user_data *) pioctl_buf->pbuf;
+ user_data->user_data_length = MIN(MAX_OTP_USER_DATA_LEN,
+ wlan_le16_to_cpu(cmd_user_data->
+ user_data_length));
+ memcpy(pmpriv->adapter, user_data->user_data, cmd_user_data->user_data,
+ user_data->user_data_length);
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_misc_otp_user_data) + user_data->user_data_length;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles the station command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *) pioctl;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int ctr;
+
+ ENTER();
+
+ /* If the command is not successful, cleanup and return failure */
+ if ((resp->result != HostCmd_RESULT_OK)
+ ) {
+ wlan_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_ret_cfg_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_ret_mac_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_ret_802_11_mac_address(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = wlan_ret_mac_multicast_adr(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = wlan_ret_802_11_scan_ext(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+ ret = wlan_ret_bgscan_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_ret_802_11_bgscan_query(pmpriv, resp, pioctl_buf);
+ PRINTM(MINFO, "CMD_RESP: BG_SCAN result is ready!\n");
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_ret_tx_power_cfg(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_802_11_RF_TX_POWER:
+ ret = wlan_ret_802_11_rf_tx_power(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_enh_power_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_ret_802_11_sleep_period(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_ret_802_11_sleep_params(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_ret_802_11_associate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = wlan_ret_802_11_deauthenticate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_ret_802_11_ad_hoc(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_ret_802_11_ad_hoc_stop(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_ret_get_log(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_ret_802_11_rssi_info(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_ret_802_11_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = wlan_ret_802_11_rf_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ ret = wlan_ret_rx_mgmt_ind(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = wlan_ret_802_11_key_material(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_ret_802_11_supplicant_pmk(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_ret_802_11_supplicant_profile(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ pmadapter->tx_buf_size =
+ (t_u16) wlan_le16_to_cpu(resp->params.tx_buf.buff_size);
+ pmadapter->tx_buf_size =
+ (pmadapter->tx_buf_size / MLAN_SDIO_BLOCK_SIZE) *
+ MLAN_SDIO_BLOCK_SIZE;
+ pmadapter->curr_tx_buf_size = pmadapter->tx_buf_size;
+ pmadapter->mp_end_port =
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port);
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+ for (ctr = 1; ctr <= MAX_PORT - pmadapter->mp_end_port; ctr++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - ctr));
+ }
+
+ pmadapter->curr_wr_port = 1;
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port),
+ pmadapter->mp_data_port_mask);
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ ret = wlan_ret_wmm_get_status(pmpriv,
+ resp->params.get_wmm_status.
+ queue_status_tlv, resp->size - S_DS_GEN);
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_ret_wmm_addts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_ret_wmm_delts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_ret_wmm_queue_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_ret_wmm_queue_stats(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_ret_wmm_ts_status(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = wlan_ret_ibss_coalescing_status(pmpriv, resp);
+ break;
+ case HostCmd_CMD_MGMT_IE_LIST:
+ ret = wlan_ret_mgmt_ie_list(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_ret_11n_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_ret_tx_bf_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_ret_sysclock_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret =
+ wlan_ret_reg_access(pmpriv->adapter, cmdresp_no, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_ret_mem_access(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_ret_inactivity_timeout(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_process(pmpriv, resp);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_ret_wifi_direct_mode(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ ret = wlan_ret_subscribe_event(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_OTP_READ_USER_DATA:
+ ret = wlan_ret_otp_user_data(pmpriv, resp, pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
new file mode 100644
index 000000000000..1ad77818995f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
@@ -0,0 +1,589 @@
+/** @file mlan_sta_event.c
+ *
+ * @brief This file contains MLAN event 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:
+ 10/13/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"
+#include "mlan_11h.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function handles link lost, deauth and
+ * disassoc events.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @return N/A
+ */
+static t_void
+wlan_handle_disconnect_event(pmlan_private pmpriv)
+{
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles disconnect event, reports disconnect
+ * to upper layer, cleans tx/rx packets,
+ * resets link state etc.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param drv_disconnect Flag indicating the driver should disconnect
+ * and flush pending packets.
+ *
+ * @return N/A
+ */
+t_void
+wlan_reset_connect_state(pmlan_private priv, t_u8 drv_disconnect)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable;
+
+ ENTER();
+
+ if (priv->media_connected != MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MINFO, "Handles disconnect event.\n");
+
+ if (drv_disconnect) {
+ priv->media_connected = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+
+ if (priv->port_ctrl_mode == MTRUE) {
+ /* Close the port on Disconnect */
+ PRINTM(MINFO, "DISC: port_status = CLOSED\n");
+ priv->port_open = MFALSE;
+ }
+ priv->scan_block = MFALSE;
+
+ /* Reset SNR/NF/RSSI values */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->rxpd_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->max_amsdu = 0;
+
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ priv->wpa_ie_len = 0;
+
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
+
+ priv->wps.session_enable = MFALSE;
+ memset(priv->adapter, (t_u8 *) & priv->wps.wps_ie, 0x00,
+ sizeof(priv->wps.wps_ie));
+
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+
+ /* Enable auto data rate */
+ priv->is_data_rate_auto = MTRUE;
+ priv->data_rate = 0;
+
+ if (priv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->adhoc_is_link_sensed = MFALSE;
+ priv->intf_state_11h.adhoc_auto_sel_chan = MTRUE;
+ }
+
+ if (drv_disconnect) {
+ /* Free Tx and Rx packets, report disconnect to upper layer */
+ wlan_clean_txrx(priv);
+
+ /* Need to erase the current SSID and BSSID info */
+ memset(pmadapter,
+ &priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));
+ }
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->pps_uapsd_mode = MFALSE;
+ pmadapter->delay_null_pkt = MFALSE;
+
+ if ((wlan_11d_is_enabled(priv)) &&
+ (priv->state_11d.user_enable_11d == DISABLE_11D)) {
+
+ priv->state_11d.enable_11d = DISABLE_11D;
+ enable = DISABLE_11D;
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11D_i, MNULL, &enable);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to enable 11D\n");
+ }
+ if (pmadapter->num_cmd_timeout && pmadapter->curr_cmd &&
+ (pmadapter->cmd_timer_is_set == MFALSE)) {
+ LEAVE();
+ return;
+ }
+
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_DISCONNECTED, MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the OBSS scan parameters to the application
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_2040_coex_event(pmlan_private pmpriv)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+ t_u8 ele_len;
+
+ ENTER();
+
+ if (pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param &&
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param->
+ ieee_hdr.element_id == OVERLAPBSSSCANPARAM) {
+ ele_len =
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param->
+ ieee_hdr.len;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM;
+ /* Copy OBSS scan parameters */
+ memcpy(pmpriv->adapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ poverlap_bss_scan_param->obss_scan_param, ele_len);
+ pevent->event_len = ele_len;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM, pevent);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_event(IN t_void * priv)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ t_u8 event_buf[100];
+ t_u8 *evt_buf = MNULL;
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ pmbuf->data_len > sizeof(eventcause))
+ DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+
+ switch (eventcause) {
+ case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+ PRINTM(MERROR,
+ "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n");
+ break;
+ case EVENT_LINK_SENSED:
+ PRINTM(MEVENT, "EVENT: LINK_SENSED\n");
+ pmpriv->adhoc_is_link_sensed = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, MNULL);
+ break;
+
+ case EVENT_DEAUTHENTICATED:
+ PRINTM(MEVENT, "EVENT: Deauthenticated\n");
+ pmadapter->dbg.num_event_deauth++;
+ wlan_handle_disconnect_event(pmpriv);
+
+ break;
+
+ case EVENT_DISASSOCIATED:
+ PRINTM(MEVENT, "EVENT: Disassociated\n");
+ pmadapter->dbg.num_event_disassoc++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_LINK_LOST:
+ PRINTM(MEVENT, "EVENT: Link lost\n");
+ pmadapter->dbg.num_event_link_lost++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM(MEVENT, "_");
+
+ /* Handle unexpected PS SLEEP event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ wlan_check_ps_cond(pmadapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE \n");
+ PRINTM(MEVENT, "|");
+ if (!pmadapter->pps_uapsd_mode &&
+ pmpriv->media_connected &&
+ (pmpriv->port_open || !pmpriv->port_ctrl_mode) &&
+ pmadapter->sleep_period.period) {
+ pmadapter->pps_uapsd_mode = MTRUE;
+ PRINTM(MEVENT, "PPS/UAPSD mode activated\n");
+ }
+ /* Handle unexpected PS AWAKE event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->tx_lock_flag = MFALSE;
+ if (pmadapter->pps_uapsd_mode && pmadapter->gen_null_pkt) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ if (!pmadapter->data_sent) {
+ if (wlan_send_null_packet(pmpriv,
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET
+ |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
+ == MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ break;
+
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ 0, 0, MNULL, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_UNICAST:
+ PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_MULTICAST:
+ PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL);
+ break;
+ case EVENT_MIB_CHANGED:
+ case EVENT_INIT_DONE:
+ break;
+
+ case EVENT_ADHOC_BCN_LOST:
+ PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n");
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, MNULL);
+ break;
+
+ case EVENT_BG_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
+ pmadapter->bgscan_reported = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
+ break;
+
+ case EVENT_PORT_RELEASE:
+ PRINTM(MEVENT, "EVENT: PORT RELEASE\n");
+ /* Open the port for e-supp mode */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ PRINTM(MINFO, "PORT_REL: port_status = OPEN\n");
+ pmpriv->port_open = MTRUE;
+ }
+ pmpriv->scan_block = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
+ break;
+
+ case EVENT_STOP_TX:
+ PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause);
+ wlan_11h_tx_disable(pmpriv); // this fn will send event up to MOAL
+ break;
+ case EVENT_START_TX:
+ PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause);
+ wlan_11h_tx_enable(pmpriv); // this fn will send event up to MOAL
+ break;
+ case EVENT_CHANNEL_SWITCH:
+ PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause);
+ /* To be handled for 'chanswann' private command */
+ break;
+ case EVENT_CHANNEL_SWITCH_ANN:
+ PRINTM(MEVENT, "EVENT: Channel Switch Announcement\n");
+ /* Here, pass up event first, as handling will send deauth */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN, MNULL);
+ wlan_11h_handle_event_chanswann(pmpriv);
+ break;
+ case EVENT_RADAR_DETECTED:
+ PRINTM(MEVENT, "EVENT: Radar Detected\n");
+
+ /* Send as passthru first, this event can cause other events */
+ memset(pmadapter, pevent, 0x00, sizeof(event_buf));
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage = RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(pmadapter);
+ } else {
+ PRINTM(MEVENT, "Ignore Event Radar Detected - handling"
+ " already in progress.\n");
+ }
+
+ break;
+
+ case EVENT_CHANNEL_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
+ /* Allocate memory for event buffer */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf);
+ if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
+ memset(pmadapter, evt_buf, 0x00, MAX_EVENT_SIZE);
+ /* Setup event buffer */
+ pevent = (pmlan_event) evt_buf;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ /* Copy event data */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause),
+ pevent->event_len);
+ /* Handle / pass event data */
+ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent);
+
+ /* Also send this event as passthru */
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ /* Now done with buffer */
+ pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
+ }
+ /* Send up this Event to unblock MOAL waitqueue */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ break;
+ case EVENT_EXT_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: EXT_SCAN Report (%#x)\n", eventcause);
+ ret = wlan_handle_event_ext_scan_report(priv, pmbuf);
+ break;
+ case EVENT_MEAS_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Measurement Report Ready (%#x)\n", eventcause);
+ wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT,
+ HostCmd_ACT_GEN_SET, 0, 0, MNULL);
+ break;
+ case EVENT_WMM_STATUS_CHANGE:
+ if (pmbuf && pmbuf->data_len
+ > sizeof(eventcause) + sizeof(MrvlIEtypesHeader_t)) {
+ PRINTM(MEVENT, "EVENT: WMM status changed: %d\n", pmbuf->data_len);
+
+ evt_buf = (pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause));
+
+ wlan_ret_wmm_get_status(pmpriv,
+ evt_buf,
+ pmbuf->data_len - sizeof(eventcause));
+ } else {
+ PRINTM(MEVENT, "EVENT: WMM status changed\n");
+ ret = wlan_cmd_wmm_status_change(pmpriv);
+ }
+ break;
+
+ case EVENT_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL);
+ break;
+ case EVENT_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL);
+ break;
+ case EVENT_MAX_FAIL:
+ PRINTM(MEVENT, "EVENT: MAX_FAIL\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL);
+ break;
+ case EVENT_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL);
+ break;
+ case EVENT_DATA_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL);
+ break;
+ case EVENT_DATA_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Data SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL);
+ break;
+ case EVENT_DATA_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_DATA_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL);
+ break;
+ case EVENT_LINK_QUALITY:
+ PRINTM(MEVENT, "EVENT: Link Quality\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL);
+ break;
+ case EVENT_PRE_BEACON_LOST:
+ PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL);
+ break;
+ case EVENT_IBSS_COALESCED:
+ PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n");
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body);
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIMEOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ wlan_11n_ba_stream_timeout(pmpriv,
+ (HostCmd_DS_11N_BATIMEOUT *) pmadapter->
+ event_body);
+ break;
+ case EVENT_RXBA_SYNC:
+ PRINTM(MEVENT, "EVENT: RXBA_SYNC\n");
+ wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
+ pmbuf->data_len - sizeof(eventcause));
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pmadapter->tx_buf_size =
+ MIN(pmadapter->curr_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
+ break;
+
+ case EVENT_WEP_ICV_ERR:
+ PRINTM(MEVENT, "EVENT: WEP ICV error\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR;
+ pevent->event_len = sizeof(Event_WEP_ICV_ERR);
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent);
+ break;
+
+ case EVENT_BW_CHANGE:
+ PRINTM(MEVENT, "EVENT: BW Change\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED;
+ pevent->event_len = sizeof(t_u8);
+ /* Copy event body from the event buffer */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent);
+ break;
+
+#ifdef WIFI_DIRECT_SUPPORT
+ case EVENT_WIFIDIRECT_GENERIC_EVENT:
+ case EVENT_WIFIDIRECT_SERVICE_DISCOVERY:
+ PRINTM(MEVENT, "EVENT: WIFIDIRECT event %d\n", eventcause);
+ /* Allocate memory for event buffer */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE,
+ MLAN_MEM_DEF, &evt_buf);
+ if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
+ pevent = (pmlan_event) evt_buf;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
+ }
+ break;
+ case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
+ PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
+ *(t_u16 *) pmadapter->event_body);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED, MNULL);
+ break;
+#endif /* WIFI_DIRECT_SUPPORT */
+
+ default:
+ PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL);
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
new file mode 100644
index 000000000000..eb715cb804c8
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
@@ -0,0 +1,5489 @@
+/** @file mlan_sta_ioctl.c
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ * 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/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_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief enable adhoc aes key
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static void
+wlan_enable_aes_key(pmlan_private pmpriv)
+{
+ mlan_ds_encrypt_key encrypt_key;
+
+ ENTER();
+
+ if (pmpriv->aes_key.key_param_set.key_len != WPA_AES_KEY_LEN) {
+ LEAVE();
+ return;
+ }
+
+ memset(pmpriv->adapter, &encrypt_key, 0, sizeof(mlan_ds_encrypt_key));
+ encrypt_key.key_len = WPA_AES_KEY_LEN;
+ encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ memcpy(pmpriv->adapter, encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, encrypt_key.key_len);
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, MNULL,
+ &encrypt_key);
+ encrypt_key.key_index &= ~MLAN_KEY_INDEX_UNICAST;
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED, MNULL, &encrypt_key);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get signal information
+ *
+ * @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_get_info_signal(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_signal)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_signal);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Signal info can be obtained only if connected */
+ if (pmpriv->media_connected == MFALSE) {
+ PRINTM(MINFO, "Can not get signal in disconnected state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @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_get_info_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @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_get_info_bss_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ BSSDescriptor_t *pbss_desc;
+ t_s32 tbl_idx = 0;
+
+ ENTER();
+
+ /* Get current BSS info */
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ /* BSS mode */
+ info->param.bss_info.bss_mode = pmpriv->bss_mode;
+
+ /* SSID */
+ memcpy(pmadapter, &info->param.bss_info.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* BSSID */
+ memcpy(pmadapter, &info->param.bss_info.bssid, &pbss_desc->mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Channel */
+ info->param.bss_info.bss_chan = pbss_desc->channel;
+
+ /* Beacon interval */
+ info->param.bss_info.beacon_interval = pbss_desc->beacon_period;
+
+ /* Band */
+ info->param.bss_info.bss_band = (t_u8) pbss_desc->bss_band;
+
+ /* Region code */
+ info->param.bss_info.region_code = pmadapter->region_code;
+
+ /* Scan table index if connected */
+ info->param.bss_info.scan_table_idx = 0;
+ if (pmpriv->media_connected == MTRUE) {
+ tbl_idx =
+ wlan_find_ssid_in_list(pmpriv, &pbss_desc->ssid,
+ pbss_desc->mac_address, pmpriv->bss_mode);
+ if (tbl_idx >= 0)
+ info->param.bss_info.scan_table_idx = tbl_idx;
+ }
+
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* Tx power information */
+ info->param.bss_info.max_power_level = pmpriv->max_tx_power_level;
+ info->param.bss_info.min_power_level = pmpriv->min_tx_power_level;
+
+ /* AdHoc state */
+ info->param.bss_info.adhoc_state = pmpriv->adhoc_state;
+
+ /* Last beacon NF */
+ info->param.bss_info.bcn_nf_last = pmpriv->bcn_nf_last;
+
+ /* wep status */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ info->param.bss_info.wep_status = MTRUE;
+ else
+ info->param.bss_info.wep_status = MFALSE;
+
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.bss_info.is_deep_sleep = pmadapter->is_deep_sleep;
+
+ /* Capability Info */
+ info->param.bss_info.capability_info = 0;
+ memcpy(pmadapter, &info->param.bss_info.capability_info,
+ &pbss_desc->cap_info, sizeof(info->param.bss_info.capability_info));
+
+ /* Listen Interval */
+ info->param.bss_info.listen_interval = pmpriv->listen_interval;
+
+ /* Association ID */
+ if (pmpriv->assoc_rsp_buf)
+ info->param.bss_info.assoc_id =
+ (t_u16) ((IEEEtypes_AssocRsp_t *) pmpriv->assoc_rsp_buf)->a_id;
+ else
+ info->param.bss_info.assoc_id = 0;
+
+ /* AP/Peer supported rates */
+ memset(pmadapter, info->param.bss_info.peer_supp_rates, 0,
+ sizeof(info->param.bss_info.peer_supp_rates));
+ memcpy(pmadapter, info->param.bss_info.peer_supp_rates,
+ pbss_desc->supported_rates,
+ MIN(sizeof(info->param.bss_info.peer_supp_rates),
+ sizeof(pbss_desc->supported_rates)));
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get information handler
+ *
+ * @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_get_info_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ switch (pget_info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ status = wlan_get_info_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ status = wlan_get_info_signal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_FW_INFO:
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
+ memcpy(pmadapter, &pget_info->param.fw_info.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
+ pget_info->param.fw_info.hw_dev_mcs_support =
+ pmadapter->hw_dev_mcs_support;
+ break;
+ case MLAN_OID_GET_BSS_INFO:
+ status = wlan_get_info_bss_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DEBUG_INFO:
+ status = wlan_get_info_debug_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_VER_EXT:
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get SNMP MIB handler
+ *
+ * @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_snmp_mib_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u16 cmd_oid = 0;
+ mlan_ds_snmp_mib *mib = MNULL;
+ t_u32 value = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ mib = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ switch (mib->sub_command) {
+ case MLAN_OID_SNMP_MIB_RTS_THRESHOLD:
+ value = mib->param.rts_threshold;
+ cmd_oid = RtsThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_FRAG_THRESHOLD:
+ value = mib->param.frag_threshold;
+ cmd_oid = FragThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_RETRY_COUNT:
+ value = mib->param.retry_count;
+ cmd_oid = ShortRetryLim_i;
+ break;
+ case MLAN_OID_SNMP_MIB_DTIM_PERIOD:
+ value = mib->param.dtim_period;
+ cmd_oid = DtimPeriod_i;
+ break;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action, cmd_oid, (t_void *) pioctl_req, &value);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Infra/Ad-hoc band 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_radio_ioctl_band_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ t_u8 i, global_band = 0;
+ t_u8 infra_band = 0;
+ t_u8 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ infra_band = (t_u8) radio_cfg->param.band_cfg.config_bands;
+ adhoc_band = (t_u8) radio_cfg->param.band_cfg.adhoc_start_band;
+ adhoc_channel = radio_cfg->param.band_cfg.adhoc_channel;
+
+ /* SET Infra band */
+ if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* SET Ad-hoc Band */
+ if ((adhoc_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!adhoc_band)
+ adhoc_band = pmadapter->adhoc_start_band;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i] && pmadapter->priv[i] != pmpriv &&
+ GET_BSS_ROLE(pmadapter->priv[i]) == MLAN_BSS_ROLE_STA)
+ global_band |= pmadapter->priv[i]->config_bands;
+ }
+ global_band |= infra_band;
+
+ if (wlan_set_regiontable
+ (pmpriv, (t_u8) pmadapter->region_code, global_band | adhoc_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_11d_set_universaltable(pmpriv, global_band | adhoc_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->config_bands = infra_band;
+ pmadapter->config_bands = global_band;
+
+ pmadapter->adhoc_start_band = adhoc_band;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ pmadapter->chan_bandwidth =
+ (t_u8) radio_cfg->param.band_cfg.sec_chan_offset;
+ /*
+ * If no adhoc_channel is supplied verify if the existing adhoc channel
+ * compiles with new adhoc_band
+ */
+ if (!adhoc_channel) {
+ if (!wlan_find_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band,
+ pmpriv->adhoc_channel)) {
+ /* Pass back the default channel */
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL;
+ if ((pmadapter->adhoc_start_band & BAND_A)
+ || (pmadapter->adhoc_start_band & BAND_AN)
+ ) {
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL_A;
+ }
+ }
+ } else { /* Return error if adhoc_band and adhoc_channel
+ combination is invalid */
+ if (!wlan_find_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band,
+ (t_u16) adhoc_channel)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->adhoc_channel = (t_u8) adhoc_channel;
+ }
+
+ if ((adhoc_band & BAND_GN)
+ || (adhoc_band & BAND_AN)
+ ) {
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else {
+ pmadapter->adhoc_11n_enabled = MFALSE;
+ }
+ } else {
+ radio_cfg->param.band_cfg.config_bands = pmpriv->config_bands; /* Infra
+ Bands
+ */
+ radio_cfg->param.band_cfg.adhoc_start_band = pmadapter->adhoc_start_band; /* Adhoc
+ Band
+ */
+ radio_cfg->param.band_cfg.adhoc_channel = pmpriv->adhoc_channel; /* Adhoc
+ Channel
+ */
+ radio_cfg->param.band_cfg.fw_bands = pmadapter->fw_bands; /* FW
+ support
+ Bands
+ */
+ PRINTM(MINFO, "Global config band = %d\n", pmadapter->config_bands);
+ radio_cfg->param.band_cfg.sec_chan_offset = pmadapter->chan_bandwidth; /* adhoc
+ channel
+ bandwidth
+ */
+
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Radio command handler
+ *
+ * @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_radio_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_radio_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_radio_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ switch (radio_cfg->sub_command) {
+ case MLAN_OID_RADIO_CTRL:
+ status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BAND_CFG:
+ status = wlan_radio_ioctl_band_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_ANT_CFG:
+ status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case MLAN_OID_REMAIN_CHAN_CFG:
+ status = wlan_radio_ioctl_remain_chan_cfg(pmadapter, pioctl_req);
+ break;
+#endif
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @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_bss_ioctl_mac_address(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pioctl_req->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ memcpy(pmadapter, &bss->param.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+
+ memcpy(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set multicast list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_set_multicast_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 old_pkt_filter;
+
+ ENTER();
+
+ old_pkt_filter = pmpriv->curr_pkt_filter;
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) {
+ PRINTM(MINFO, "Enable Promiscuous mode\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ /* Multicast */
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ if (bss->param.multicast_list.mode == MLAN_ALL_MULTI_MODE) {
+ PRINTM(MINFO, "Enabling All Multicast!\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ if (bss->param.multicast_list.num_multicast_addr) {
+ PRINTM(MINFO, "Set multicast list=%d\n",
+ bss->param.multicast_list.num_multicast_addr);
+ /* Set multicast addresses to firmware */
+ if (old_pkt_filter == pmpriv->curr_pkt_filter) {
+ /* Send request to firmware */
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *) pioctl_req,
+ &bss->param.multicast_list);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* Send request to firmware */
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &bss->param.multicast_list);
+ }
+ }
+ }
+ }
+ PRINTM(MINFO, "old_pkt_filter=0x%x, curr_pkt_filter=0x%x\n", old_pkt_filter,
+ pmpriv->curr_pkt_filter);
+ if (old_pkt_filter != pmpriv->curr_pkt_filter) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @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_bss_ioctl_get_channel_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp;
+ t_u32 i, j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((wlan_11d_is_enabled(pmpriv) &&
+ pmpriv->media_connected == MTRUE) &&
+ ((pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ||
+ (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ pmpriv->adhoc_state != ADHOC_STARTED))
+ ) {
+ t_u8 chan_no;
+ t_u8 band;
+
+ parsed_region_chan_11d_t *parsed_region_chan = MNULL;
+ parsed_region_chan_11d_t region_chan;
+
+ BSSDescriptor_t *pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* If country IE is present in the associated AP then return the
+ channel list from country IE else return it from the learning table */
+
+ if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ &region_chan) == MLAN_STATUS_SUCCESS) {
+
+ parsed_region_chan = &region_chan;
+ } else {
+ parsed_region_chan = &pmadapter->parsed_region_chan;
+ }
+
+ PRINTM(MINFO, "no_of_chan=%d\n", parsed_region_chan->no_of_chan);
+
+ for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && (i < parsed_region_chan->no_of_chan); i++) {
+ chan_no = parsed_region_chan->chan_pwr[i].chan;
+ band = parsed_region_chan->chan_pwr[i].band;
+ PRINTM(MINFO, "band=%d, chan_no=%d\n", band, chan_no);
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].channel =
+ (t_u32) chan_no;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
+ (t_u32) wlan_11d_chan_2_freq(pmadapter, chan_no, band);
+ bss->param.chanlist.num_of_chan++;
+ }
+ } else {
+ for (j = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ cfp = pmadapter->region_channel[j].pcfp;
+ for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && pmadapter->region_channel[j].valid
+ && cfp && (i < pmadapter->region_channel[j].num_cfp); i++) {
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].
+ channel = (t_u32) cfp->channel;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
+ (t_u32) cfp->freq;
+ bss->param.chanlist.num_of_chan++;
+ cfp++;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "num of channel=%d\n", bss->param.chanlist.num_of_chan);
+
+ LEAVE();
+ return ret;
+}
+
+/** Highest channel used in 2.4GHz band */
+#define MAX_CHANNEL_BAND_B (14)
+
+/** Highest frequency used in 2.4GHz band */
+#define MAX_FREQUENCY_BAND_B (2484)
+
+/**
+ * @brief Set/Get BSS channel
+ *
+ * @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_bss_ioctl_channel(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp = MNULL;
+ ENTER();
+
+ if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
+ pmpriv->curr_bss_params.band,
+ (t_u16) pmpriv->curr_bss_params.
+ bss_descriptor.channel);
+ if (cfp) {
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(chan_freq) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+ }
+ if (!bss->param.bss_chan.channel && !bss->param.bss_chan.freq) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmadapter->adhoc_start_band & BAND_AN)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ else if (pmadapter->adhoc_start_band & BAND_A)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ if (bss->param.bss_chan.channel) {
+ if (bss->param.bss_chan.channel <= MAX_CHANNEL_BAND_B)
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter, BAND_B,
+ (t_u16) bss->param.bss_chan.
+ channel);
+ if (!cfp) {
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter, BAND_A,
+ (t_u16) bss->param.bss_chan.
+ channel);
+ if (cfp) {
+ if (pmadapter->adhoc_11n_enabled)
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ else
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ } else {
+ if (bss->param.bss_chan.freq <= MAX_FREQUENCY_BAND_B)
+ cfp =
+ wlan_find_cfp_by_band_and_freq(pmadapter, BAND_B,
+ bss->param.bss_chan.freq);
+ if (!cfp) {
+ cfp =
+ wlan_find_cfp_by_band_and_freq(pmadapter, BAND_A,
+ bss->param.bss_chan.freq);
+ if (cfp) {
+ if (pmadapter->adhoc_11n_enabled)
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ else
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ }
+ if (!cfp || !cfp->channel) {
+ PRINTM(MERROR, "Invalid channel/freq\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+
+ }
+ pmpriv->adhoc_channel = (t_u8) cfp->channel;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BSS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_mode(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_mode = pmpriv->bss_mode;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ goto exit;
+ }
+
+ if ((pmpriv->bss_mode == bss->param.bss_mode) ||
+ (bss->param.bss_mode == MLAN_BSS_MODE_AUTO)) {
+ PRINTM(MINFO, "Already set to required mode! No change!\n");
+ pmpriv->bss_mode = bss->param.bss_mode;
+ goto exit;
+ }
+
+ if (pmpriv->bss_mode != MLAN_BSS_MODE_AUTO)
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ else
+ ret = wlan_disconnect(pmpriv, pioctl_req, MNULL);
+
+ if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO)
+ pmpriv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
+ pmpriv->bss_mode = bss->param.bss_mode;
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ pmpriv->port_ctrl_mode = MTRUE;
+ else
+ pmpriv->port_ctrl_mode = MFALSE;
+
+ if ((pmpriv->bss_mode != MLAN_BSS_MODE_AUTO)
+ ) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @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_bss_ioctl_start(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_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ t_s32 i = -1;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ /* Before ASSOC REQ, If "port ctrl" mode is enabled, move the port to
+ CLOSED state */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ PRINTM(MINFO, "bss_ioctl_start(): port_state=CLOSED\n");
+ pmpriv->prior_port_status = pmpriv->port_open;
+ pmpriv->port_open = MFALSE;
+ }
+ pmpriv->scan_block = MFALSE;
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (!bss->param.ssid_bssid.idx ||
+ bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
+ /* Search for the requested SSID in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ if (memcmp
+ (pmadapter, &bss->param.ssid_bssid.bssid, zero_mac,
+ sizeof(zero_mac)))
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ (t_u8 *) & bss->param.ssid_bssid.
+ bssid, MLAN_BSS_MODE_INFRA);
+ else
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_INFRA);
+ } else {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.
+ bssid, MLAN_BSS_MODE_INFRA);
+ }
+ } else {
+ /* use bsslist index number to assoicate */
+ i = wlan_is_network_compatible(pmpriv,
+ bss->param.ssid_bssid.idx - 1,
+ pmpriv->bss_mode);
+ }
+ if (i >= 0) {
+ PRINTM(MINFO, "SSID found in scan list ... associating...\n");
+
+ /* Clear any past association response stored for application
+ retrieval */
+ pmpriv->assoc_rsp_size = 0;
+ ret = wlan_associate(pmpriv, pioctl_req,
+ &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ } else { /* i >= 0 */
+ PRINTM(MERROR,
+ "SSID not found in scan list: ssid=%s, %02x:%02x:%02x:%02x:%02x:%02x, idx=%d\n",
+ bss->param.ssid_bssid.ssid.ssid,
+ bss->param.ssid_bssid.bssid[0],
+ bss->param.ssid_bssid.bssid[1],
+ bss->param.ssid_bssid.bssid[2],
+ bss->param.ssid_bssid.bssid[3],
+ bss->param.ssid_bssid.bssid[4],
+ bss->param.ssid_bssid.bssid[5],
+ (int) bss->param.ssid_bssid.idx);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto start_ssid_done;
+ }
+ } else {
+ /* Adhoc mode */
+ /* If the requested SSID matches current SSID, return */
+ if (bss->param.ssid_bssid.ssid.ssid_len &&
+ (!wlan_ssid_cmp
+ (pmadapter, &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ &bss->param.ssid_bssid.ssid))) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto start_ssid_done;
+ }
+
+ /* Exit Adhoc mode first */
+ PRINTM(MINFO, "Sending Adhoc Stop\n");
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ if (ret)
+ goto start_ssid_done;
+
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+
+ if (!bss->param.ssid_bssid.idx ||
+ bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
+ /* Search for the requested network in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_IBSS);
+ } else {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.
+ bssid, MLAN_BSS_MODE_IBSS);
+ }
+ } else {
+ /* use bsslist index number to assoicate */
+ i = wlan_is_network_compatible(pmpriv,
+ bss->param.ssid_bssid.idx - 1,
+ pmpriv->bss_mode);
+ }
+
+ if (i >= 0) {
+ PRINTM(MINFO, "Network found in scan list ... joining ...\n");
+ ret =
+ wlan_adhoc_join(pmpriv, pioctl_req, &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ if (pmpriv->adhoc_aes_enabled)
+ wlan_enable_aes_key(pmpriv);
+ } else { /* i >= 0 */
+ PRINTM(MINFO, "Network not found in the list, "
+ "creating adhoc with ssid = %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ ret =
+ wlan_adhoc_start(pmpriv, pioctl_req,
+ &bss->param.ssid_bssid.ssid);
+ if (ret)
+ goto start_ssid_done;
+ if (pmpriv->adhoc_aes_enabled)
+ wlan_enable_aes_key(pmpriv);
+ }
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ start_ssid_done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Stop BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_stop(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ ENTER();
+
+ ret = wlan_disconnect(pmpriv, pioctl_req, &bss->param.bssid);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IBSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_ibss_channel(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->media_connected == MFALSE) {
+ bss->param.bss_chan.channel = pmpriv->adhoc_channel;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ pmpriv->adhoc_channel = (t_u8) bss->param.bss_chan.channel;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_CHANNEL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &bss->param.bss_chan.channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @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_bss_ioctl_beacon_interval(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bcn_interval = pmpriv->beacon_period;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.bcn_interval =
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period;
+ } else
+ pmpriv->beacon_period = (t_u16) bss->param.bcn_interval;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @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_bss_ioctl_atim_window(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.atim_window = pmpriv->atim_window;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.atim_window =
+ pmpriv->curr_bss_params.bss_descriptor.atim_window;
+ } else
+ pmpriv->atim_window = (t_u16) bss->param.atim_window;
+
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Query embe
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status
+wlan_query_passphrase(mlan_private * priv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ssid_bssid *ssid_bssid = MNULL;
+ mlan_ds_passphrase sec_pp;
+ int i = 0;
+ BSSDescriptor_t *pbss_desc;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ ssid_bssid = &bss->param.ssid_bssid;
+
+ memset(pmadapter, &sec_pp, 0, sizeof(mlan_ds_passphrase));
+ sec_pp.psk_type = MLAN_PSK_QUERY;
+ if (ssid_bssid->ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(priv, (t_u8 *) & ssid_bssid->bssid,
+ MLAN_BSS_MODE_AUTO);
+ if (i >= 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &sec_pp.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+ } else
+ memcpy(pmadapter, &sec_pp.bssid, &ssid_bssid->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memcpy(pmadapter, &sec_pp.ssid, &ssid_bssid->ssid,
+ sizeof(mlan_802_11_ssid));
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_SUPPLICANT_PMK,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, &sec_pp);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_bss_ioctl_find_bss(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pmpriv->ewpa_query) {
+ if (wlan_query_passphrase(pmpriv, pioctl_req) == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "Find BSS ioctl: query passphrase\n");
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+ }
+ }
+ ret = wlan_find_bss(pmpriv, pioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief BSS command handler
+ *
+ * @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_bss_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_bss)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_bss);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_START:
+ status = wlan_bss_ioctl_start(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_STOP:
+ status = wlan_bss_ioctl_stop(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MODE:
+ status = wlan_bss_ioctl_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL:
+ status = wlan_bss_ioctl_channel(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL_LIST:
+ status = wlan_bss_ioctl_get_channel_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MAC_ADDR:
+ status = wlan_bss_ioctl_mac_address(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MULTICAST_LIST:
+ status = wlan_bss_ioctl_set_multicast_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_FIND_BSS:
+ status = wlan_bss_ioctl_find_bss(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_BCN_INTERVAL:
+ status = wlan_bss_ioctl_beacon_interval(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_ATIM_WINDOW:
+ status = wlan_bss_ioctl_atim_window(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_CHANNEL:
+ status = wlan_bss_ioctl_ibss_channel(pmadapter, pioctl_req);
+ break;
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case MLAN_OID_BSS_ROLE:
+ status = wlan_bss_ioctl_bss_role(pmadapter, pioctl_req);
+ break;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ case MLAN_OID_WIFI_DIRECT_MODE:
+ status = wlan_bss_ioctl_wifi_direct_mode(pmadapter, pioctl_req);
+ break;
+#endif
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get supported rates
+ *
+ * @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_rate_ioctl_get_supported_rate(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->param.rate_band_cfg.config_bands &&
+ rate->param.rate_band_cfg.bss_mode)
+ wlan_get_active_data_rates(pmpriv, rate->param.rate_band_cfg.bss_mode,
+ rate->param.rate_band_cfg.config_bands,
+ rate->param.rates);
+ else
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
+ pmpriv->config_bands : pmadapter->
+ adhoc_start_band, rate->param.rates);
+ pioctl_req->data_read_written =
+ MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @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_rate_ioctl_get_data_rate(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_rate)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_rate);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ switch (rate->sub_command) {
+ case MLAN_OID_RATE_CFG:
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DATA_RATE:
+ status = wlan_rate_ioctl_get_data_rate(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SUPPORTED_RATES:
+ status = wlan_rate_ioctl_get_supported_rate(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cmd_no Firmware command number used to retrieve power values
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_get_power(IN pmlan_adapter pmadapter,
+ IN t_u16 cmd_no, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd_no,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power 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_power_ioctl_set_power(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_power_cfg *power = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ t_u16 dbm = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ if (!power->param.power_cfg.is_power_auto) {
+ dbm = (t_u16) power->param.power_cfg.power_level;
+ if ((dbm < pmpriv->min_tx_power_level) ||
+ (dbm > pmpriv->max_tx_power_level)) {
+ PRINTM(MERROR,
+ "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ dbm, pmpriv->min_tx_power_level, pmpriv->max_tx_power_level);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MRVDRV_SIZE_OF_CMD_BUFFER, MLAN_MEM_DEF, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ if (!power->param.power_cfg.is_power_auto) {
+ txp_cfg->mode = 1;
+ pg_tlv = (MrvlTypes_Power_Group_t *) (buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = 4 * sizeof(Power_Group_t);
+ pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ /* Power group for modulation class HR/DSSS */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x03;
+ pg->modulation_class = MOD_CLASS_HR_DSSS;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg++;
+ /* Power group for modulation class OFDM */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x07;
+ pg->modulation_class = MOD_CLASS_OFDM;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg++;
+ /* Power group for modulation class HTBW20 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg->ht_bandwidth = HT_BW_20;
+ pg++;
+ /* Power group for modulation class HTBW40 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg->ht_bandwidth = HT_BW_40;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get modulation class from rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate_index Rate index
+ *
+ * @return 0 fail, otherwise return modulation class
+ */
+static int
+wlan_get_modulation_class(pmlan_adapter pmadapter, int rate_index)
+{
+ int tx_mcs_supp = GET_TXMCSSUPP(pmadapter->usr_dev_mcs_support);
+ ENTER();
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3) {
+ LEAVE();
+ return MOD_CLASS_HR_DSSS;
+ } else if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7) {
+ LEAVE();
+ return MOD_CLASS_OFDM;
+ } else if (rate_index >= MLAN_RATE_INDEX_MCS0 &&
+ rate_index <= MLAN_RATE_INDEX_MCS127) {
+ if ((rate_index > MLAN_RATE_INDEX_MCS7 &&
+ rate_index <= MLAN_RATE_INDEX_MCS15) && (tx_mcs_supp < 2)) {
+ PRINTM(MERROR,
+ "HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n",
+ rate_index, pmadapter->usr_dev_mcs_support);
+ LEAVE();
+ return 0;
+ }
+ LEAVE();
+ return MOD_CLASS_HT;
+ }
+ PRINTM(MERROR, "Invalid rate index = %d supplied!\n", rate_index);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set extended power 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_power_ioctl_set_power_ext(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_power_cfg *power = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ int mod_class;
+ t_u32 data[4];
+ t_u8 ht_bw;
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MRVDRV_SIZE_OF_CMD_BUFFER,
+ MLAN_MEM_DEF, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ memcpy(pmadapter, (t_u8 *) & data,
+ (t_u8 *) power->param.power_ext.power_data, sizeof(data));
+ switch (power->param.power_ext.len) {
+ case 1:
+ if (data[0] == 0xFF)
+ txp_cfg->mode = 0;
+ else {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ break;
+ case 2:
+ case 4:
+ ht_bw = (data[0] & TX_RATE_HT_BW40_BIT) ? HT_BW_40 : HT_BW_20;
+ data[0] &= ~TX_RATE_HT_BW40_BIT;
+ if (!(mod_class = wlan_get_modulation_class(pmadapter, data[0]))) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ht_bw && mod_class != MOD_CLASS_HT) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ txp_cfg->mode = 1;
+ pg_tlv =
+ (MrvlTypes_Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = sizeof(Power_Group_t);
+ pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ pg->modulation_class = (t_u8) mod_class;
+ pg->first_rate_code = (t_u8) data[0];
+ pg->last_rate_code = (t_u8) data[0];
+ if (mod_class == MOD_CLASS_OFDM) {
+ pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
+ pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
+ } else if (mod_class == MOD_CLASS_HT) {
+ pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
+ pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
+ pg->ht_bandwidth = ht_bw;
+ }
+ pg->power_min = (t_s8) data[1];
+ pg->power_max = (t_s8) data[1];
+ if (power->param.power_ext.len == 4) {
+ pg->power_max = (t_s8) data[2];
+ pg->power_step = (t_s8) data[3];
+ }
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power configuration command handler
+ *
+ * @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_power_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_power_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_power_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ switch (power->sub_command) {
+ case MLAN_OID_POWER_CFG:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(pmadapter,
+ HostCmd_CMD_TXPWR_CFG,
+ pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power(pmadapter, pioctl_req);
+ break;
+
+ case MLAN_OID_POWER_CFG_EXT:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(pmadapter,
+ HostCmd_CMD_TXPWR_CFG,
+ pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power_ext(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set power save configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ps_mode Power save mode
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl_ps_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u16 ps_mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 sub_cmd;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ sub_cmd = (pmadapter->ps_mode == Wlan802_11PowerModePSP) ?
+ EN_AUTO_PS : DIS_AUTO_PS;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, sub_cmd,
+ BITMAP_STA_PS, (t_void *) pioctl_req, MNULL);
+ if ((ret == MLAN_STATUS_SUCCESS) && (sub_cmd == DIS_AUTO_PS)) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, MNULL, MNULL);
+ }
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, (t_void *) pioctl_req, MNULL);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Inactivity timeout extend
+ *
+ * @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_pm_ioctl_inactivity_timeout(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pmcfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_INACTIVITY_TIMEOUT_EXT,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & pmcfg->param.inactivity_to);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable Auto Deep Sleep
+ *
+ * @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_set_auto_deep_sleep(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv =
+ (pmlan_private) pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.auto_ds ==
+ DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ mode = EN_AUTO_PS;
+ } else {
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "Auto Deep Sleep: off\n");
+ mode = DIS_AUTO_PS;
+ }
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.idletime)
+ auto_ds.idletime =
+ ((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ idletime;
+ else
+ auto_ds.idletime = pmadapter->idle_time;
+ /* note: the command could be queued and executed later if there is
+ command in progress. */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ (t_u16) mode,
+ BITMAP_AUTO_DS, (t_void *) pioctl_req, &auto_ds);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @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_set_get_sleep_pd(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0, sleep_pd = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ sleep_pd = (t_u16) pm_cfg->param.sleep_period;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PERIOD,
+ cmd_action, 0, (t_void *) pioctl_req, &sleep_pd);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration 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_set_get_ps_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32) pmadapter->null_pkt_interval;
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32) pmadapter->multiple_dtim;
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32) pmadapter->local_listen_interval;
+ pm_cfg->param.ps_cfg.adhoc_awake_period =
+ (t_u32) pmadapter->adhoc_awake_period;
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32) pmadapter->bcn_miss_time_out;
+ pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
+ pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
+ } else {
+ if (pm_cfg->param.ps_cfg.ps_null_interval)
+ pmadapter->null_pkt_interval =
+ (t_u16) pm_cfg->param.ps_cfg.ps_null_interval;
+ else
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32) pmadapter->null_pkt_interval;
+ if (pm_cfg->param.ps_cfg.multiple_dtim_interval)
+ pmadapter->multiple_dtim =
+ (t_u16) pm_cfg->param.ps_cfg.multiple_dtim_interval;
+ else
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32) pmadapter->multiple_dtim;
+ if (((t_s32) pm_cfg->param.ps_cfg.listen_interval) ==
+ MRVDRV_LISTEN_INTERVAL_DISABLE)
+ pmadapter->local_listen_interval = 0;
+ else if (pm_cfg->param.ps_cfg.listen_interval)
+ pmadapter->local_listen_interval =
+ (t_u16) pm_cfg->param.ps_cfg.listen_interval;
+ else
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32) pmadapter->local_listen_interval;
+ if (pm_cfg->param.ps_cfg.adhoc_awake_period)
+ pmadapter->adhoc_awake_period =
+ (t_u16) pm_cfg->param.ps_cfg.adhoc_awake_period;
+ else
+ pm_cfg->param.ps_cfg.adhoc_awake_period =
+ (t_u32) pmadapter->adhoc_awake_period;
+ if (pm_cfg->param.ps_cfg.bcn_miss_timeout)
+ pmadapter->bcn_miss_time_out =
+ (t_u16) pm_cfg->param.ps_cfg.bcn_miss_timeout;
+ else
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32) pmadapter->bcn_miss_time_out;
+ if (pm_cfg->param.ps_cfg.delay_to_ps != DELAY_TO_PS_UNCHANGED)
+ pmadapter->delay_to_ps = (t_u16) pm_cfg->param.ps_cfg.delay_to_ps;
+ else
+ pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
+ if (pm_cfg->param.ps_cfg.ps_mode)
+ pmadapter->enhanced_ps_mode = (t_u16) pm_cfg->param.ps_cfg.ps_mode;
+ else
+ pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get/Set the sleep parameters
+ *
+ * @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_set_get_sleep_params(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_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PARAMS,
+ cmd_action, 0, (t_void *) pioctl_req,
+ &pm_cfg->param.sleep_params);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power save command handler
+ *
+ * @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_pm_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ switch (pm->sub_command) {
+ case MLAN_OID_PM_CFG_IEEE_PS:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pm->param.ps_mode)
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ status =
+ wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ case MLAN_ACT_GET:
+ status =
+ wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_HS_CFG:
+ status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_INACTIVITY_TO:
+ status = wlan_pm_ioctl_inactivity_timeout(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_DEEP_SLEEP:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ PRINTM(MMSG, "Station already in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ } else if (!pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_OFF) {
+ PRINTM(MMSG,
+ "Station already not in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status = wlan_set_auto_deep_sleep(pmadapter, pioctl_req);
+ break;
+ case MLAN_ACT_GET:
+ if (pmadapter->is_deep_sleep) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = pmadapter->idle_time;
+ } else
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_PS_CFG:
+ status = wlan_set_get_ps_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PD:
+ status = wlan_set_get_sleep_pd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PARAMS:
+ status = wlan_set_get_sleep_params(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_INFO:
+ status = wlan_get_pm_info(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WMM status
+ *
+ * @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_wmm_ioctl_enable(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_wmm_cfg *wmm = MNULL;
+ ENTER();
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.wmm_enable = (t_u32) pmpriv->wmm_required;
+ else
+ pmpriv->wmm_required = (t_u8) wmm->param.wmm_enable;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WMM QoS configuration
+ *
+ * @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_wmm_ioctl_qos(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_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.qos_cfg = pmpriv->wmm_qosinfo;
+ else {
+ pmpriv->wmm_qosinfo = wmm->param.qos_cfg;
+ }
+
+ pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for add a TSPEC
+ *
+ * @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_wmm_ioctl_addts_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_ADDTS_REQ,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.addts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for delete a TSPEC
+ *
+ * @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_wmm_ioctl_delts_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_DELTS_REQ,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.delts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get a specified AC Queue's parameters
+ *
+ * @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_wmm_ioctl_queue_config(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_CONFIG,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.q_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief To get and start/stop queue stats on a WMM AC
+ *
+ * @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_wmm_ioctl_queue_stats(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_STATS,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.q_stats);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM AC queues
+ *
+ * @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_wmm_ioctl_queue_status(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+ mlan_ds_wmm_queue_status *pqstatus = MNULL;
+ WmmAcStatus_t *pac_status = MNULL;
+ mlan_wmm_ac_e ac_idx;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ pqstatus = (mlan_ds_wmm_queue_status *) & cfg->param.q_status;
+
+ for (ac_idx = WMM_AC_BK; ac_idx <= WMM_AC_VO; ac_idx++) {
+ pac_status = &pmpriv->wmm.ac_status[ac_idx];
+
+ /* Firmware status */
+ pqstatus->ac_status[ac_idx].flow_required = pac_status->flow_required;
+ pqstatus->ac_status[ac_idx].flow_created = pac_status->flow_created;
+ pqstatus->ac_status[ac_idx].disabled = pac_status->disabled;
+
+ /* ACM bit reflected in firmware status (redundant) */
+ pqstatus->ac_status[ac_idx].wmm_acm = pac_status->flow_required;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM Traffic Streams
+ *
+ * @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_wmm_ioctl_ts_status(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_TS_STATUS,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.ts_status);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WMM configuration handler
+ *
+ * @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_wmm_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wmm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wmm_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ switch (wmm->sub_command) {
+ case MLAN_OID_WMM_CFG_ENABLE:
+ status = wlan_wmm_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QOS:
+ status = wlan_wmm_ioctl_qos(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_ADDTS:
+ status = wlan_wmm_ioctl_addts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_DELTS:
+ status = wlan_wmm_ioctl_delts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_CONFIG:
+ status = wlan_wmm_ioctl_queue_config(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATS:
+ status = wlan_wmm_ioctl_queue_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATUS:
+ status = wlan_wmm_ioctl_queue_status(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_TS_STATUS:
+ status = wlan_wmm_ioctl_ts_status(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_wpa_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ ENTER();
+
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wpa_ie)) {
+ PRINTM(MERROR, "failed to copy, WPA IE is too big \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->adapter, priv->wpa_ie, ie_data_ptr, ie_len);
+ priv->wpa_ie_len = (t_u8) ie_len;
+ PRINTM(MIOCTL, "Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "Wpa_ie", priv->wpa_ie, priv->wpa_ie_len);
+ if (priv->wpa_ie[0] == WPA_IE) {
+ priv->sec_info.wpa_enabled = MTRUE;
+ } else if (priv->wpa_ie[0] == RSN_IE) {
+ priv->sec_info.wpa2_enabled = MTRUE;
+ } else {
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+ } else {
+ memset(priv->adapter, priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = 0;
+ PRINTM(MINFO, "Reset Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_wapi_ie(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ ENTER();
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wapi_ie)) {
+ PRINTM(MWARN, "failed to copy, WAPI IE is too big \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->adapter, priv->wapi_ie, ie_data_ptr, ie_len);
+ priv->wapi_ie_len = (t_u8) ie_len;
+ PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie, priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = (t_u8) ie_len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @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_sec_ioctl_wapi_enable(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_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE) {
+ wlan_set_wapi_ie(pmpriv, MNULL, 0);
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI key
+ *
+ * @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_sec_ioctl_set_wapi_key(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_sec_cfg *sec = MNULL;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Port Control status
+ *
+ * @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_sec_ioctl_port_ctrl_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->port_ctrl_mode)
+ sec->param.port_ctrl_enabled = MTRUE;
+ else
+ sec->param.port_ctrl_enabled = MFALSE;
+ } else {
+ if (sec->param.port_ctrl_enabled) {
+ pmpriv->port_ctrl_mode = MTRUE;
+ pmpriv->port_open = MFALSE;
+ } else {
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ pmpriv->port_ctrl_mode = MFALSE;
+ /* Cleanup the bypass TX queue */
+ wlan_cleanup_bypass_txq(pmadapter);
+ }
+ }
+ }
+ PRINTM(MINFO, "port_ctrl: port_ctrl_mode=%d port_open=%d\n",
+ pmpriv->port_ctrl_mode, pmpriv->port_open);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get authentication mode
+ *
+ * @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_sec_ioctl_auth_mode(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_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.auth_mode = pmpriv->sec_info.authentication_mode;
+ else {
+ pmpriv->sec_info.authentication_mode = sec->param.auth_mode;
+ if (pmpriv->sec_info.authentication_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get encryption mode
+ *
+ * @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_sec_ioctl_encrypt_mode(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_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.encrypt_mode = pmpriv->sec_info.encryption_mode;
+ else {
+ pmpriv->sec_info.encryption_mode = sec->param.encrypt_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPA status
+ *
+ * @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_sec_ioctl_wpa_enable(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_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wpa_ie_len)
+ sec->param.wpa_enabled = MTRUE;
+ else
+ sec->param.wpa_enabled = MFALSE;
+ } else {
+ if (sec->param.wpa_enabled == MFALSE) {
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ /** clear adhoc aes flag, when WPA enabled */
+ pmpriv->adhoc_aes_enabled = MFALSE;
+ pmpriv->aes_key.key_param_set.key_len = 0;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WEP keys
+ *
+ * @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_sec_ioctl_set_wep_key(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_sec_cfg *sec = MNULL;
+ mrvl_wep_key_t *pwep_key = MNULL;
+ int index;
+
+ ENTER();
+
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+ pwep_key = &pmpriv->wep_key[pmpriv->wep_key_curr_index];
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_DEFAULT) {
+ index = pmpriv->wep_key_curr_index;
+ } else
+ index = sec->param.encrypt_key.key_index;
+ if ((sec->param.encrypt_key.key_disable == MTRUE) ||
+ (sec->param.encrypt_key.key_remove == MTRUE)) {
+ pmpriv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ /* remove key */
+ if (sec->param.encrypt_key.key_remove == MTRUE) {
+ memset(pmadapter, &pmpriv->wep_key[index], 0,
+ sizeof(mrvl_wep_key_t));
+ }
+ } else {
+ if (sec->param.encrypt_key.key_len) {
+ pwep_key = &pmpriv->wep_key[index];
+ /* Cleanup */
+ memset(pmadapter, pwep_key, 0, sizeof(mrvl_wep_key_t));
+ /* Copy the key in the driver */
+
+ memcpy(pmadapter, pwep_key->key_material,
+ sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ pwep_key->key_index = index;
+ pwep_key->key_length = sec->param.encrypt_key.key_len;
+ if (pmpriv->sec_info.wep_status != Wlan802_11WEPEnabled) {
+ /*
+ * The status is set as Key Absent
+ * so as to make sure we display the
+ * keys when iwlist mlanX key is used
+ */
+ pmpriv->sec_info.wep_status = Wlan802_11WEPKeyAbsent;
+ }
+ }
+ if (sec->param.encrypt_key.is_current_wep_key == MTRUE) {
+ /* Copy the required key as the current key */
+ pwep_key = &pmpriv->wep_key[index];
+ if (!pwep_key->key_length) {
+ PRINTM(MERROR, "Key %d not set,so cannot enable it\n", index);
+ pioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pmpriv->wep_key_curr_index = (t_u16) index;
+ pmpriv->sec_info.wep_status = Wlan802_11WEPEnabled;
+ }
+ }
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ /* Send request to firmware */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ && pwep_key->key_length) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0, MNULL, &pmpriv->curr_pkt_filter);
+ if (ret)
+ goto exit;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ } else {
+ if (pwep_key->key_length) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret)
+ goto exit;
+ }
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA key
+ *
+ * @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_sec_ioctl_set_wpa_key(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_sec_cfg *sec = MNULL;
+ t_u8 broadcast_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ t_u8 remove_key = MFALSE;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ /* Current driver only supports key length of up to 32 bytes */
+ if (sec->param.encrypt_key.key_len > MLAN_MAX_KEY_LENGTH) {
+ PRINTM(MERROR, "Key length is incorrect\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if ((pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) &&
+ pmpriv->sec_info.wpa_enabled) {
+ /*
+ * IBSS/WPA-None uses only one key (Group) for both receiving and
+ * sending unicast and multicast packets.
+ */
+ /* Send the key as PTK to firmware */
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ MNULL, &sec->param.encrypt_key);
+ if (ret)
+ goto exit;
+
+ /* Send the key as GTK to firmware */
+ sec->param.encrypt_key.key_index = ~MLAN_KEY_INDEX_UNICAST;
+ }
+
+ if (sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN) {
+ /** back up adhoc AES key */
+ memset(pmpriv->adapter, pmpriv->aes_key.key_param_set.key, 0,
+ sizeof(pmpriv->aes_key.key_param_set.key));
+ pmpriv->aes_key.key_param_set.key_len = sec->param.encrypt_key.key_len;
+ memcpy(pmpriv->adapter, pmpriv->aes_key.key_param_set.key,
+ sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key_len);
+ }
+
+ /** only adhoc aes key_index = MLAN_KEY_INDEX_UNICAST */
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN
+ && sec->param.encrypt_key.key_index & MLAN_KEY_INDEX_UNICAST) {
+ t_u8 zero_key_material[WPA_AES_KEY_LEN];
+ memset(pmadapter, zero_key_material, 0, sizeof(zero_key_material));
+ if (memcmp
+ (pmadapter, sec->param.encrypt_key.key_material, zero_key_material,
+ WPA_AES_KEY_LEN)) {
+ PRINTM(MINFO, "Adhoc AES Enabled.\n");
+ pmpriv->adhoc_aes_enabled = MTRUE;
+ remove_key = MFALSE;
+ } else {
+ PRINTM(MINFO, "Adhoc AES Disabled.\n");
+ pmpriv->adhoc_aes_enabled = MFALSE;
+ /** clear adhoc AES key */
+ remove_key = MTRUE;
+ pmpriv->aes_key.key_param_set.key_len = 0;
+ }
+ }
+
+ if (memcmp
+ (pmadapter, sec->param.encrypt_key.mac_addr, broadcast_mac_addr,
+ MLAN_MAC_ADDR_LENGTH))
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+
+ if (remove_key == MTRUE) {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ !(KEY_INFO_ENABLED),
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get security keys
+ *
+ * @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_sec_ioctl_get_key(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_sec_cfg *sec = MNULL;
+ int index;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+
+ if ((sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_UNICAST) &&
+ (sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN)) {
+ if (pmpriv->adhoc_aes_enabled == MTRUE &&
+ (pmpriv->aes_key.key_param_set.key_len == WPA_AES_KEY_LEN)) {
+ HEXDUMP("Get ADHOCAES Key", pmpriv->aes_key.key_param_set.key,
+ WPA_AES_KEY_LEN);
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, WPA_AES_KEY_LEN);
+ LEAVE();
+ return ret;
+ } else {
+ PRINTM(MERROR, " ADHOCAES key is not set yet!\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ }
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+
+ if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ || (pmpriv->sec_info.wep_status == Wlan802_11WEPKeyAbsent)
+ || pmpriv->sec_info.ewpa_enabled
+ || pmpriv->sec_info.wpa_enabled
+ || pmpriv->sec_info.wpa2_enabled || pmpriv->adhoc_aes_enabled) {
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ if (sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_DEFAULT) {
+ if ((pmpriv->wep_key[pmpriv->wep_key_curr_index].key_length) &&
+ (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)) {
+ index = pmpriv->wep_key_curr_index;
+ sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material, MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->
+ wep_key[index].
+ key_length));
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH, pmpriv->wep_key[index].key_length);
+ } else if ((pmpriv->sec_info.wpa_enabled)
+ || (pmpriv->sec_info.ewpa_enabled)
+ || (pmpriv->sec_info.wpa2_enabled)
+ || (pmpriv->sec_info.wapi_enabled)
+ || (pmpriv->adhoc_aes_enabled)
+ ) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->aes_key.
+ key_param_set.
+ key_len));
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH, pmpriv->aes_key.key_param_set.key_len);
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ } else {
+ index = sec->param.encrypt_key.key_index;
+ if (pmpriv->wep_key[index].key_length) {
+ sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material, MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->
+ wep_key[index].
+ key_length));
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH, pmpriv->wep_key[index].key_length);
+ } else if ((pmpriv->sec_info.wpa_enabled)
+ || (pmpriv->sec_info.ewpa_enabled)
+ || (pmpriv->sec_info.wpa2_enabled)
+ || (pmpriv->sec_info.wapi_enabled)
+ || (pmpriv->adhoc_aes_enabled)
+ ) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set security key(s)
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_encrypt_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.encrypt_key.is_wapi_key)
+ status = wlan_sec_ioctl_set_wapi_key(pmadapter, pioctl_req);
+ else if (sec->param.encrypt_key.key_len > MAX_WEP_KEY_SIZE)
+ status = wlan_sec_ioctl_set_wpa_key(pmadapter, pioctl_req);
+ else
+ status = wlan_sec_ioctl_set_wep_key(pmadapter, pioctl_req);
+ } else {
+ status = wlan_sec_ioctl_get_key(pmadapter, pioctl_req);
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA passphrase for esupplicant
+ *
+ * @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_sec_ioctl_passphrase(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_sec_cfg *sec = MNULL;
+ t_u16 cmd_action = 0;
+ BSSDescriptor_t *pbss_desc;
+ int i = 0;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) {
+ if (sec->param.passphrase.ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & sec->param.passphrase.
+ bssid, MLAN_BSS_MODE_AUTO);
+ if (i >= 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &sec->param.passphrase.ssid,
+ &pbss_desc->ssid, sizeof(mlan_802_11_ssid));
+ memset(pmadapter, &sec->param.passphrase.bssid, 0,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO, "PSK_QUERY: found ssid=%s\n",
+ sec->param.passphrase.ssid.ssid);
+ }
+ } else
+ memset(pmadapter, &sec->param.passphrase.bssid, 0,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PMK,
+ cmd_action,
+ 0, (t_void *) pioctl_req, &sec->param.passphrase);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get esupplicant status
+ *
+ * @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_sec_ioctl_ewpa_enable(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_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ sec->param.ewpa_enabled = pmpriv->sec_info.ewpa_enabled;
+ } else {
+ pmpriv->sec_info.ewpa_enabled = (t_u8) sec->param.ewpa_enabled;
+ PRINTM(MINFO, "Set: ewpa_enabled = %d\n",
+ (int) pmpriv->sec_info.ewpa_enabled);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupplicant mode
+ *
+ * @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_sec_ioctl_esupp_mode(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];
+ t_u16 cmd_action = 0;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR,
+ "Cannot set esupplicant mode configuration while connected.\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.rsn_mode ||
+ (sec->param.esupp_mode.rsn_mode & RSN_TYPE_VALID_BITS)
+ != sec->param.esupp_mode.rsn_mode) {
+ PRINTM(MERROR, "Invalid RSN mode\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.act_paircipher ||
+ (sec->param.esupp_mode.act_paircipher & EMBED_CIPHER_VALID_BITS)
+ != sec->param.esupp_mode.act_paircipher) {
+ PRINTM(MERROR, "Invalid pairwise cipher\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.act_groupcipher ||
+ (sec->param.esupp_mode.act_groupcipher & EMBED_CIPHER_VALID_BITS)
+ != sec->param.esupp_mode.act_groupcipher) {
+ PRINTM(MERROR, "Invalid group cipher\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET_CURRENT;
+ }
+
+ /* Send request to firmware */
+ if (sec) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PROFILE,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &sec->param.esupp_mode);
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PROFILE,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Security configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_sec_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_sec_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ switch (sec->sub_command) {
+ case MLAN_OID_SEC_CFG_AUTH_MODE:
+ status = wlan_sec_ioctl_auth_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_MODE:
+ status = wlan_sec_ioctl_encrypt_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WPA_ENABLED:
+ status = wlan_sec_ioctl_wpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WAPI_ENABLED:
+ status = wlan_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED:
+ status = wlan_sec_ioctl_port_ctrl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_KEY:
+ status = wlan_sec_ioctl_encrypt_key(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PASSPHRASE:
+ status = wlan_sec_ioctl_passphrase(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_EWPA_ENABLED:
+ status = wlan_sec_ioctl_ewpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ESUPP_MODE:
+ status = wlan_sec_ioctl_esupp_mode(pmadapter, pioctl_req);
+ break;
+
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Append/Reset IE buffer.
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command. This function is the main body
+ * for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
+ *
+ * Data is appended to an existing buffer and then wrapped in a passthrough
+ * TLV in the command API to the firmware. The firmware treats the data
+ * as a transparent passthrough to the transmitted management frame.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to iwreq structure
+ * @param ie_len Length of the IE or IE block passed in ie_data_ptr
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_VendorHeader_t *pvendor_ie;
+ const t_u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+ const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+ ENTER();
+
+ /* If the passed length is zero, reset the buffer */
+ if (!ie_len) {
+ priv->gen_ie_buf_len = 0;
+ priv->wps.session_enable = MFALSE;
+ wlan_set_wpa_ie_helper(priv, MNULL, 0);
+ } else if (!ie_data_ptr) {
+ /* MNULL check */
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+
+ pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+ /* Test to see if it is a WPA IE, if not, then it is a gen IE */
+ if (((pvendor_ie->element_id == WPA_IE)
+ &&
+ (!memcmp
+ (priv->adapter, pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
+ || (pvendor_ie->element_id == RSN_IE)
+ ) {
+
+ /* IE is a WPA/WPA2 IE so call set_wpa function */
+ ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+ priv->wps.session_enable = MFALSE;
+ } else if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_set_wapi_ie(priv, ie_data_ptr, ie_len);
+ } else
+ if ((pvendor_ie->element_id == WPS_IE) &&
+ (priv->wps.session_enable == MFALSE) &&
+ (!memcmp
+ (priv->adapter, pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
+ /*
+ * Discard first two byte (Element ID and Length)
+ * because they are not needed in the case of setting WPS_IE
+ */
+ if (pvendor_ie->len > 4) {
+ memcpy(priv->adapter, (t_u8 *) & priv->wps.wps_ie, ie_data_ptr,
+ ie_len);
+ HEXDUMP("wps_ie", (t_u8 *) & priv->wps.wps_ie,
+ priv->wps.wps_ie.vend_hdr.len + 2);
+ } else {
+ /* Only wps oui exist, reset driver wps buffer */
+ memset(priv->adapter, (t_u8 *) & priv->wps.wps_ie, 0x00,
+ sizeof(priv->wps.wps_ie));
+ PRINTM(MINFO, "wps_ie cleared\n");
+ }
+ } else {
+ /*
+ * Verify that the passed length is not larger than the available
+ * space remaining in the buffer
+ */
+ if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
+
+ /* Test to see if it is a WPS IE, if so, enable wps session
+ flag */
+ pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+ if ((pvendor_ie->element_id == WPS_IE)
+ &&
+ (!memcmp
+ (priv->adapter, pvendor_ie->oui, wps_oui,
+ sizeof(wps_oui)))) {
+ priv->wps.session_enable = MTRUE;
+ PRINTM(MINFO, "WPS Session Enabled.\n");
+ }
+
+ /* Append the passed data to the end of the genIeBuffer */
+ memcpy(priv->adapter, priv->gen_ie_buf + priv->gen_ie_buf_len,
+ ie_data_ptr, ie_len);
+ /* Increment the stored buffer length by the size passed */
+ priv->gen_ie_buf_len += ie_len;
+ } else {
+ /* Passed data does not fit in the remaining buffer space */
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+
+ /* Return MLAN_STATUS_SUCCESS, or MLAN_STATUS_FAILURE for error case */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @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_misc_ioctl_wws_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ t_u32 enable = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ enable = misc_cfg->param.wws_cfg;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action,
+ WwsMode_i, (t_void *) pioctl_req, &enable);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get 11D status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11d_cfg_ioctl_enable(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_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MIOCTL,
+ "11D setting cannot be changed while interface is active.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "11D: 11dcfg SET=%d\n", pcfg_11d->param.enable_11d);
+
+ /* Compare with current settings */
+ if (pmpriv->state_11d.user_enable_11d != pcfg_11d->param.enable_11d) {
+ ret =
+ wlan_11d_enable(pmpriv, pioctl_req,
+ (state_11d_t) pcfg_11d->param.enable_11d);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ PRINTM(MINFO, "11D: same as current setting, do nothing\n");
+ }
+ } else {
+ pcfg_11d->param.enable_11d = (t_u32) pmpriv->state_11d.user_enable_11d;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ PRINTM(MINFO, "11D: 11dcfg GET=%d\n", pcfg_11d->param.enable_11d);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Clear 11D chan table
+ *
+ * @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_11d_clr_chan_table(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];
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "11D: 11dclrtbl SET\n");
+
+ if (wlan_11d_clear_parsedtable(pmpriv) == MLAN_STATUS_SUCCESS)
+ PRINTM(MINFO,
+ "11D: cleared parsed_region_chan (now no_of_chan=%d)\n",
+ pmadapter->parsed_region_chan.no_of_chan);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 11D configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11d_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ status = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ switch (pcfg_11d->sub_command) {
+ case MLAN_OID_11D_CFG_ENABLE:
+ status = wlan_11d_cfg_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11D_CLR_CHAN_TABLE:
+ status = wlan_11d_clr_chan_table(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11D_DOMAIN_INFO:
+ status = wlan_11d_cfg_domain_info(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ exit:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief WPS configuration handler
+ *
+ * @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_wps_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wps_cfg *pwps = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wps_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wps_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) pioctl_req->pbuf;
+ switch (pwps->sub_command) {
+ case MLAN_OID_WPS_CFG_SESSION:
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pwps->param.wps_session == MLAN_WPS_CFG_SESSION_START)
+ pmpriv->wps.session_enable = MTRUE;
+ } else {
+ pwps->param.wps_session = (t_u32) pmpriv->wps.session_enable;
+ pioctl_req->data_read_written = sizeof(t_u32);
+ PRINTM(MINFO, "wpscfg GET=%d\n", pwps->param.wps_session);
+ }
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Read/write adapter register
+ *
+ * @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_reg_mem_ioctl_reg_rw(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0, cmd_no;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ switch (reg_mem->param.reg_rw.type) {
+ case MLAN_REG_MAC:
+ cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
+ break;
+ case MLAN_REG_BBP:
+ cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
+ break;
+ case MLAN_REG_RF:
+ cmd_no = HostCmd_CMD_RF_REG_ACCESS;
+ break;
+ case MLAN_REG_CAU:
+ cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, cmd_no, cmd_action,
+ 0, (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.reg_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @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_reg_mem_ioctl_read_eeprom(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_EEPROM_ACCESS,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.rd_eeprom);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/write memory of device
+ *
+ * @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_reg_mem_ioctl_mem_rw(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MEM_ACCESS,
+ cmd_action, 0,
+ (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.mem_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief register memory access handler
+ *
+ * @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_reg_mem_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_reg_mem *reg_mem = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_reg_mem)) {
+ PRINTM(MWARN, "MLAN REG_MEM IOCTL length is too short\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_reg_mem);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ switch (reg_mem->sub_command) {
+ case MLAN_OID_REG_RW:
+ status = wlan_reg_mem_ioctl_reg_rw(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_EEPROM_RD:
+ status = wlan_reg_mem_ioctl_read_eeprom(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MEM_RW:
+ status = wlan_reg_mem_ioctl_mem_rw(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief 802.11h ad-hoc start channel check
+ *
+ * @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_11h_channel_check_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmpriv->adhoc_state = ADHOC_STARTING;
+
+ if ((pmadapter->adhoc_start_band & BAND_A)
+ || (pmadapter->adhoc_start_band & BAND_AN)
+ ) {
+ if (pmpriv->intf_state_11h.adhoc_auto_sel_chan)
+ pmpriv->adhoc_channel = wlan_11h_get_adhoc_start_channel(pmpriv);
+
+ /*
+ * Check if the region and channel requires a channel availability
+ * check.
+ */
+ if (wlan_11h_radar_detect_required(pmpriv, pmpriv->adhoc_channel)
+ && !wlan_11h_is_channel_under_nop(pmadapter, pmpriv->adhoc_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);
+
+ /* Check for radar on the channel */
+ ret = wlan_11h_issue_radar_detect(pmpriv, pioctl_req,
+ pmpriv->adhoc_channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h set/get local power constraint
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_ioctl_local_power_constraint(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ t_s8 *plocalpower = &pmadapter->state_11h.usr_def_power_constraint;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ ds_11hcfg->param.usr_local_power_constraint = *plocalpower;
+ else
+ *plocalpower = ds_11hcfg->param.usr_local_power_constraint;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief 11h configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11h_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
+ PRINTM(MWARN, "MLAN 11H IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+
+ switch (ds_11hcfg->sub_command) {
+ case MLAN_OID_11H_CHANNEL_CHECK:
+ status = wlan_11h_channel_check_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11H_LOCAL_POWER_CONSTRAINT:
+ status = wlan_11h_ioctl_local_power_constraint(pmadapter, pioctl_req);
+ break;
+#if defined(DFS_TESTING_SUPPORT)
+ case MLAN_OID_11H_DFS_TESTING:
+ status = wlan_11h_ioctl_dfs_testing(pmadapter, pioctl_req);
+ break;
+#endif
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @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_misc_ioctl_gen_ie(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_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ switch (misc->param.gen_ie.type) {
+ case MLAN_IE_TYPE_GEN_IE:
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.gen_ie.len = pmpriv->wpa_ie_len;
+ memcpy(pmadapter, misc->param.gen_ie.ie_data, pmpriv->wpa_ie,
+ misc->param.gen_ie.len);
+ } else {
+ wlan_set_gen_ie_helper(pmpriv, misc->param.gen_ie.ie_data,
+ (t_u16) misc->param.gen_ie.len);
+ }
+ break;
+ case MLAN_IE_TYPE_ARP_FILTER:
+ memset(pmadapter, pmadapter->arp_filter, 0,
+ sizeof(pmadapter->arp_filter));
+ if (misc->param.gen_ie.len > ARP_FILTER_MAX_BUF_SIZE) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MERROR, "Invalid ARP Filter Size\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else if (misc->param.gen_ie.len <= sizeof(MrvlIEtypesHeader_t)) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MINFO, "Clear ARP filter\n");
+ } else {
+ memcpy(pmadapter, pmadapter->arp_filter, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ pmadapter->arp_filter_size = misc->param.gen_ie.len;
+ HEXDUMP("ArpFilter", pmadapter->arp_filter,
+ pmadapter->arp_filter_size);
+ }
+ break;
+ default:
+ PRINTM(MERROR, "Invalid IE type\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_ds_misc_gen_ie) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @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_misc_ioctl_region(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_misc_cfg *misc = MNULL;
+ int i;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.region_code = pmadapter->region_code;
+ } else {
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (misc->param.region_code == region_code_index[i]) {
+ pmadapter->region_code = (t_u16) misc->param.region_code;
+ break;
+ }
+ }
+ /* It's unidentified region code */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ PRINTM(MERROR, "Region Code not identified\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->cfp_code_bg = misc->param.region_code;
+ pmadapter->cfp_code_a = misc->param.region_code;
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->config_bands | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Perform warm reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING
+ */
+static mlan_status
+wlan_misc_ioctl_warm_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_s32 i = 0;
+
+ ENTER();
+
+ /** Init all the head nodes and free all the locks here */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ wlan_free_priv(pmadapter->priv[i]);
+ }
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+
+ /* Initialize private structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ wlan_init_priv(pmadapter->priv[i]);
+ }
+ }
+
+ /* Restart the firmware */
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+
+ /* Issue firmware initialize commands for first BSS, for other interfaces
+ it will be called after getting the last init command response of
+ previous interface */
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmadapter->pwarm_reset_ioctl_req = pioctl_req;
+ pmpriv->ops.init_cmd(pmpriv, MTRUE);
+
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief Reconfigure SDIO multiport aggregation parameters
+ *
+ * @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_misc_ioctl_sdio_mpa_ctrl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_ds_misc_sdio_mpa_ctrl *mpa_ctrl = MNULL;
+
+ ENTER();
+
+ mpa_ctrl = &misc->param.mpa_ctrl;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MMSG, "SDIO MPA CTRL: not allowed in connected state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_enable > 1) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_enable > 1) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_buf_size || mpa_ctrl->rx_buf_size) {
+
+ wlan_free_sdio_mpa_buffers(pmadapter);
+
+ if (mpa_ctrl->tx_buf_size > 0)
+ pmadapter->mpa_tx.buf_size = mpa_ctrl->tx_buf_size;
+
+ if (mpa_ctrl->rx_buf_size > 0)
+ pmadapter->mpa_rx.buf_size = mpa_ctrl->rx_buf_size;
+
+ if (wlan_alloc_sdio_mpa_buffers(pmadapter,
+ pmadapter->mpa_tx.buf_size,
+ pmadapter->mpa_rx.buf_size) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ if (mpa_ctrl->tx_max_ports > 0)
+ pmadapter->mpa_tx.pkt_aggr_limit = mpa_ctrl->tx_max_ports;
+ if (mpa_ctrl->rx_max_ports > 0)
+ pmadapter->mpa_rx.pkt_aggr_limit = mpa_ctrl->rx_max_ports;
+
+ pmadapter->mpa_tx.enabled = (t_u8) mpa_ctrl->tx_enable;
+ pmadapter->mpa_rx.enabled = (t_u8) mpa_ctrl->rx_enable;
+
+ } else {
+ mpa_ctrl->tx_enable = (t_u16) pmadapter->mpa_tx.enabled;
+ mpa_ctrl->rx_enable = (t_u16) pmadapter->mpa_rx.enabled;
+ mpa_ctrl->tx_buf_size = (t_u16) pmadapter->mpa_tx.buf_size;
+ mpa_ctrl->rx_buf_size = (t_u16) pmadapter->mpa_rx.buf_size;
+ mpa_ctrl->tx_max_ports = (t_u16) pmadapter->mpa_tx.pkt_aggr_limit;
+ mpa_ctrl->rx_max_ports = (t_u16) pmadapter->mpa_rx.pkt_aggr_limit;
+ }
+
+ exit:
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief Set/Get system clock 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_misc_ioctl_sysclock(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.sys_clock);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function softreset command to firmware
+ *
+ * @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_misc_ioctl_soft_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SOFT_RESET,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get the MAC control 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
+ */
+mlan_status
+wlan_misc_ioctl_mac_control(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.mac_ctrl = pmpriv->curr_pkt_filter;
+ } else {
+ pmpriv->curr_pkt_filter = misc->param.mac_ctrl;
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ cmd_action, 0,
+ (t_void *) pioctl_req, &misc->param.mac_ctrl);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the thermal reading
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_thermal(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Thermal reading setting is not allowed!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action, Thermal_i, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set subscribe event
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_subscribe_evt(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_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 command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &misc->param.subscribe_event);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set ARP filter based on IP address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ipv4_addr ipv4 Address
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_ipaddr_arp_filter(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 ipv4_addr)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf;
+ arpfilter_header *arpfilter = MNULL;
+ filter_entry *entry = MNULL;
+ t_u32 len;
+
+ ENTER();
+
+ pcb->moal_malloc(pmadapter->pmoal_handle, MRVDRV_SIZE_OF_CMD_BUFFER,
+ MLAN_MEM_DEF, &buf);
+ if (!buf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Construct the ARP filter TLV */
+ arpfilter = (arpfilter_header *) buf;
+ arpfilter->type = wlan_cpu_to_le16(TLV_TYPE_ARP_FILTER);
+
+ if (ipv4_addr) {
+ arpfilter->len = wlan_cpu_to_le16(sizeof(filter_entry) * 3);
+ entry = (filter_entry *) (buf + sizeof(arpfilter_header));
+ entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_BROADCAST);
+ entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ARP);
+ entry->ipv4_addr = wlan_cpu_to_le32(ipv4_addr);
+ entry++;
+ entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_UNICAST);
+ entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ANY);
+ entry->ipv4_addr = wlan_cpu_to_le32(IPV4_ADDR_ANY);
+ entry++;
+ entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_MULTICAST);
+ entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ANY);
+ entry->ipv4_addr = wlan_cpu_to_le32(IPV4_ADDR_ANY);
+ } else
+ arpfilter->len = 0;
+
+ /* Update the total length */
+ len = sizeof(arpfilter_header) + wlan_le16_to_cpu(arpfilter->len);
+
+ memset(pmadapter, pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
+ if (len > ARP_FILTER_MAX_BUF_SIZE) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MERROR, "Invalid ARP Filter Size\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else if (len <= sizeof(MrvlIEtypesHeader_t)) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MINFO, "Clear ARP filter\n");
+ } else {
+ memcpy(pmadapter, pmadapter->arp_filter, buf, len);
+ pmadapter->arp_filter_size = len;
+ HEXDUMP("ArpFilter", pmadapter->arp_filter, pmadapter->arp_filter_size);
+ }
+
+ done:
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+ LEAVE();
+ return ret;
+}
+
+#define FLTR_BUF_IP_OFFSET 39
+/**
+ * @brief Enable/Disable Auto ARP resonse
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ipv4_addr ipv4 Address
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_ipaddr_auto_arp_resp(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 ipv4_addr)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ds_misc_cmd *hostcmd;
+ t_u32 buf_len = 0;
+ t_u8 *buf, *filter;
+ t_u8 fltr_buf[] = { 0x01, 0x10, 0x30, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x01, 0xff, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08,
+ 0x06, 0x02, 0x02, 0x14, 0x00, 0x00, 0x00, 0x01,
+ 0x41, 0x44, 0x01, 0x00, 0x00, 0x00, 0x01, 0xc0,
+ 0xa8, 0x00, 0x68, 0x04, 0x02, 0x2e, 0x00, 0x00,
+ 0x00, 0x01, 0x41, 0x44
+ };
+
+ ENTER();
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd),
+ MLAN_MEM_DEF, (t_u8 **) & hostcmd);
+
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+
+ /* Prepare hostcmd buffer */
+ hostcmd_hdr = (HostCmd_DS_GEN *) (buf);
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ mefcmd = (HostCmd_DS_MEF_CFG *) (buf + S_DS_GEN);
+ buf_len = S_DS_GEN;
+
+ if (!ipv4_addr) {
+ PRINTM(MINFO, "Disable Auto ARP Response\n");
+ mefcmd->criteria = wlan_cpu_to_le32(0);
+ mefcmd->nentries = wlan_cpu_to_le16(0);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ } else {
+ /* Event bit (bit2) of HS conditions should be masked out */
+ mefcmd->criteria =
+ wlan_cpu_to_le32(pmpriv->adapter->hs_cfg.conditions & ~MBIT(2));
+ mefcmd->nentries = wlan_cpu_to_le16(1);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ filter = buf + buf_len;
+ memcpy(pmpriv->adapter, filter, fltr_buf, sizeof(fltr_buf));
+ memcpy(pmpriv->adapter, &filter[FLTR_BUF_IP_OFFSET], &ipv4_addr,
+ sizeof(ipv4_addr));
+ buf_len += sizeof(fltr_buf);
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = buf_len;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0, 0, 0, (t_void *) pioctl_req, (t_void *) hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) hostcmd);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MEF 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
+ */
+mlan_status
+wlan_misc_ioctl_mef_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_misc_mef_cfg *mef_cfg =
+ &((mlan_ds_misc_cfg *) pioctl_req->pbuf)->param.mef_cfg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ mlan_ds_misc_cmd *hostcmd = MNULL;
+ t_u32 buf_len = 0;
+ t_u8 *buf, *filter;
+ t_u8 fltr_buf[] = { 0x02, 0x00, 0x2f, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x5e, 0x03, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x41, 0x06, 0x00, 0x00, 0x00,
+ 0x01, 0xff, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x45, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x33, 0x33, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x45
+ };
+
+ ENTER();
+
+ /* GET operation */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ /* TODO: need to store for get operation */
+ goto done;
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd),
+ MLAN_MEM_DEF, (t_u8 **) & hostcmd);
+
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+
+ /* Prepare hostcmd buffer */
+ hostcmd_hdr = (HostCmd_DS_GEN *) (buf);
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ mefcmd = (HostCmd_DS_MEF_CFG *) (buf + S_DS_GEN);
+ buf_len = S_DS_GEN;
+
+ switch (mef_cfg->sub_id) {
+ case MEF_CFG_DISABLE:
+ PRINTM(MINFO, "Disable MEF\n");
+ mefcmd->criteria = wlan_cpu_to_le32(0);
+ mefcmd->nentries = wlan_cpu_to_le16(0);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ break;
+ case MEF_CFG_RX_FILTER_ENABLE:
+ PRINTM(MINFO, "Enable Rx filter\n");
+ mefcmd->criteria = wlan_cpu_to_le32((MBIT(3) | MBIT(0)));
+ mefcmd->nentries = wlan_cpu_to_le16(1);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ filter = buf + buf_len;
+ memcpy(pmpriv->adapter, filter, fltr_buf, sizeof(fltr_buf));
+ buf_len += sizeof(fltr_buf);
+ break;
+ case MEF_CFG_AUTO_ARP_RESP:
+ PRINTM(MINFO, "Enable auto ARP response\n");
+ // TODO
+ break;
+ case MEF_CFG_HOSTCMD:
+ PRINTM(MINFO, "MEF hostcmd from MOAL\n");
+ filter = buf + buf_len;
+ memcpy(pmpriv->adapter, filter, mef_cfg->param.cmd_buf.cmd,
+ mef_cfg->param.cmd_buf.len);
+ buf_len += mef_cfg->param.cmd_buf.len;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid sub ID parameter\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ break;
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = buf_len;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0, 0, 0, (t_void *) pioctl_req, (t_void *) hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ done:
+ if (hostcmd)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) hostcmd);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ipaddr 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
+ */
+mlan_status
+wlan_misc_ioctl_ipaddr_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 ipv4_addr;
+
+ ENTER();
+
+ /* GET operation */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ memcpy(pmadapter, misc->param.ipaddr_cfg.ip_addr,
+ pmpriv->ip_addr, IPADDR_LEN);
+ misc->param.ipaddr_cfg.op_code = pmpriv->op_code;
+ goto done;
+ }
+ /* only one IP is supported in current firmware */
+ memcpy(pmadapter, &ipv4_addr, misc->param.ipaddr_cfg.ip_addr[0],
+ sizeof(t_u32));
+
+ if (misc->param.ipaddr_cfg.op_code != MLAN_IPADDR_OP_IP_REMOVE &&
+ !ipv4_addr) {
+ PRINTM(MERROR, "Invalid IPv4 address\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (misc->param.ipaddr_cfg.op_code & MLAN_IPADDR_OP_ARP_FILTER)
+ ret = wlan_ipaddr_arp_filter(pmadapter, pioctl_req, ipv4_addr);
+ else if (pmpriv->op_code & MLAN_IPADDR_OP_ARP_FILTER)
+ ret = wlan_ipaddr_arp_filter(pmadapter, pioctl_req, 0);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ if (misc->param.ipaddr_cfg.op_code & MLAN_IPADDR_OP_AUTO_ARP_RESP)
+ ret = wlan_ipaddr_auto_arp_resp(pmadapter, pioctl_req, ipv4_addr);
+ else if (pmpriv->op_code & MLAN_IPADDR_OP_AUTO_ARP_RESP)
+ ret = wlan_ipaddr_auto_arp_resp(pmadapter, pioctl_req, 0);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+
+ /* Save the values in MLAN */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ pmpriv->op_code = misc->param.ipaddr_cfg.op_code;
+ memcpy(pmadapter, pmpriv->ip_addr,
+ misc->param.ipaddr_cfg.ip_addr, IPADDR_LEN);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief CFP code 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
+ */
+mlan_status
+wlan_misc_ioctl_cfp_code_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_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_ds_misc_cfp_code *cfp_code = MNULL;
+ t_u32 region_bg = 0;
+ t_u32 region_a = 0;
+ int i;
+
+ ENTER();
+
+ cfp_code = &misc->param.cfp_code;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* Save the values in MLAN */
+ if (!cfp_code->cfp_code_bg)
+ cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (cfp_code->cfp_code_bg == region_code_index[i]) {
+ region_bg = cfp_code->cfp_code_bg;
+ break;
+ }
+ }
+ if (!region_bg) {
+ for (i = 0; i < MRVDRV_MAX_CFP_CODE_BG; i++) {
+ /* Use the CFP code to search for the index */
+ if (cfp_code->cfp_code_bg == cfp_code_index_bg[i])
+ break;
+ }
+ if (i >= MRVDRV_MAX_CFP_CODE_BG) {
+ PRINTM(MERROR, "CFP Code not identified for BG\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (!cfp_code->cfp_code_a)
+ cfp_code->cfp_code_a = pmadapter->cfp_code_a;
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (cfp_code->cfp_code_a == region_code_index[i]) {
+ region_a = cfp_code->cfp_code_a;
+ break;
+ }
+ }
+ if (!region_a) {
+ for (i = 0; i < MRVDRV_MAX_CFP_CODE_A; i++) {
+ /* Use the CFP code to search for the index */
+ if (cfp_code->cfp_code_a == cfp_code_index_a[i])
+ break;
+ }
+ if (i >= MRVDRV_MAX_CFP_CODE_A) {
+ PRINTM(MERROR, "CFP Code not identified for A\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ pmadapter->cfp_code_bg = (t_u8) cfp_code->cfp_code_bg;
+ pmadapter->cfp_code_a = (t_u8) cfp_code->cfp_code_a;
+ if (region_bg && region_a && (region_bg == region_a))
+ pmadapter->region_code = pmadapter->cfp_code_a;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->config_bands | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else {
+ /* GET operation */
+ cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
+ cfp_code->cfp_code_a = pmadapter->cfp_code_a;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets up country code 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_misc_ioctl_country_code(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_misc_country_code *country_code = MNULL;
+ mlan_ds_misc_cfg *cfg_misc = MNULL;
+ t_u8 cfp_bg = 0, cfp_a = 0;
+
+ ENTER();
+
+ cfg_misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ country_code = &cfg_misc->param.country_code;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* Update region code and table based on country code */
+ if (wlan_misc_country_2_cfp_table_code(pmadapter,
+ country_code->country_code,
+ &cfp_bg, &cfp_a)) {
+ PRINTM(MERROR, "Country code not found!\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->cfp_code_bg = cfp_bg;
+ pmadapter->cfp_code_a = cfp_a;
+ if (cfp_bg && cfp_a && (cfp_bg == cfp_a))
+ pmadapter->region_code = cfp_a;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
+ pmadapter->config_bands | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memcpy(pmadapter, pmadapter->country_code,
+ country_code->country_code, COUNTRY_CODE_LEN);
+ } else {
+ /* GET operation */
+ memcpy(pmadapter, country_code->country_code,
+ pmadapter->country_code, COUNTRY_CODE_LEN);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Miscellaneous configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ switch (misc->sub_command) {
+ case MLAN_OID_MISC_GEN_IE:
+ status = wlan_misc_ioctl_gen_ie(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_REGION:
+ status = wlan_misc_ioctl_region(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WARM_RESET:
+ status = wlan_misc_ioctl_warm_reset(pmadapter, pioctl_req);
+ break;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ case MLAN_OID_MISC_SDIO_MPA_CTRL:
+ status = wlan_misc_ioctl_sdio_mpa_ctrl(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_HOST_CMD:
+ status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SYS_CLOCK:
+ status = wlan_misc_ioctl_sysclock(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WWS:
+ status = wlan_misc_ioctl_wws_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_INIT_SHUTDOWN:
+ status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SOFT_RESET:
+ status = wlan_misc_ioctl_soft_reset(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CUSTOM_IE:
+ status = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MTRUE);
+ break;
+ case MLAN_OID_MISC_MAC_CONTROL:
+ status = wlan_misc_ioctl_mac_control(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_MEF_CFG:
+ status = wlan_misc_ioctl_mef_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_RX_MGMT_IND:
+ status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
+ break;
+#ifdef DEBUG_LEVEL1
+ case MLAN_OID_MISC_DRVDBG:
+ status = wlan_set_drvdbg(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_IP_ADDR:
+ status = wlan_misc_ioctl_ipaddr_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CFP_CODE:
+ status = wlan_misc_ioctl_cfp_code_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_COUNTRY_CODE:
+ status = wlan_misc_ioctl_country_code(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_THERMAL:
+ status = wlan_misc_ioctl_thermal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SUBSCRIBE_EVENT:
+ status = wlan_misc_ioctl_subscribe_evt(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_OTP_USER_DATA:
+ status = wlan_misc_otp_user_data(pmadapter, pioctl_req);
+ break;
+ default:
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get scan configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param action Set/Get
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_set_get_scan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 action)
+{
+ mlan_ds_scan *scan = MNULL;
+
+ ENTER();
+
+ scan = (mlan_ds_scan *) pioctl_req->pbuf;
+ if (action == MLAN_ACT_GET) {
+ scan->param.scan_cfg.scan_type = (t_u32) pmadapter->scan_type;
+ scan->param.scan_cfg.scan_mode = pmadapter->scan_mode;
+ scan->param.scan_cfg.scan_probe = (t_u32) pmadapter->scan_probes;
+ scan->param.scan_cfg.scan_time.specific_scan_time =
+ (t_u32) pmadapter->specific_scan_time;
+ scan->param.scan_cfg.scan_time.active_scan_time =
+ (t_u32) pmadapter->active_scan_time;
+ scan->param.scan_cfg.scan_time.passive_scan_time =
+ (t_u32) pmadapter->passive_scan_time;
+ scan->param.scan_cfg.ext_scan = pmadapter->ext_scan;
+ } else {
+ if (scan->param.scan_cfg.scan_type)
+ pmadapter->scan_type = (t_u8) scan->param.scan_cfg.scan_type;
+ if (scan->param.scan_cfg.scan_mode)
+ pmadapter->scan_mode = scan->param.scan_cfg.scan_mode;
+ if (scan->param.scan_cfg.scan_probe)
+ pmadapter->scan_probes = (t_u16) scan->param.scan_cfg.scan_probe;
+ if (scan->param.scan_cfg.scan_time.specific_scan_time)
+ pmadapter->specific_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.specific_scan_time;
+ if (scan->param.scan_cfg.scan_time.active_scan_time)
+ pmadapter->active_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.active_scan_time;
+ if (scan->param.scan_cfg.scan_time.passive_scan_time)
+ pmadapter->passive_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.passive_scan_time;
+ pmadapter->ext_scan = scan->param.scan_cfg.ext_scan;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get scan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_scan_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *pscan;
+
+ ENTER();
+
+ pscan = (mlan_ds_scan *) pioctl_req->pbuf;
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG)
+ goto start_config;
+ if (pmadapter->scan_processing && pioctl_req->action == MLAN_ACT_SET &&
+ pscan->sub_command != MLAN_OID_SCAN_CANCEL) {
+ PRINTM(MINFO, "Scan already in process...\n");
+ LEAVE();
+ return status;
+ }
+
+ if (pmpriv->scan_block && pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "Scan is blocked during association...\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ LEAVE();
+ return status;
+ }
+ start_config:
+ /* Set scan */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+
+ switch (pscan->sub_command) {
+ case MLAN_OID_SCAN_NORMAL:
+ status = wlan_scan_networks(pmpriv, pioctl_req, MNULL);
+ break;
+ case MLAN_OID_SCAN_SPECIFIC_SSID:
+ status =
+ wlan_scan_specific_ssid(pmpriv, pioctl_req,
+ &pscan->param.scan_req.scan_ssid);
+ break;
+ case MLAN_OID_SCAN_USER_CONFIG:
+ status = wlan_scan_networks(pmpriv, pioctl_req,
+ (wlan_user_scan_cfg *) pscan->param.
+ user_scan.scan_cfg_buf);
+ break;
+ case MLAN_OID_SCAN_CONFIG:
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_SET);
+ break;
+ case MLAN_OID_SCAN_CANCEL:
+ wlan_flush_scan_queue(pmadapter);
+ break;
+ case MLAN_OID_SCAN_TABLE_FLUSH:
+ status = wlan_flush_scan_table(pmadapter);
+ break;
+ case MLAN_OID_SCAN_BGSCAN_CONFIG:
+ /* Send request to firmware */
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req,
+ pscan->param.user_scan.scan_cfg_buf);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ if ((status == MLAN_STATUS_SUCCESS) &&
+ (pscan->sub_command != MLAN_OID_SCAN_TABLE_FLUSH) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CANCEL) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CONFIG)) {
+ PRINTM(MINFO, "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ }
+ /* Get scan */
+ else {
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG) {
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_GET);
+ } else if (pscan->sub_command == MLAN_OID_SCAN_GET_CURRENT_BSS) {
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ } else {
+ if (pmadapter->bgscan_reported) {
+ pmadapter->bgscan_reported = MFALSE;
+ /* Clear the previous scan result */
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO,
+ "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ } else {
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
+ pioctl_req->data_read_written = sizeof(mlan_scan_resp) +
+ MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ }
+
+ LEAVE();
+ return status;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param psec_pp A pointer to mlan_ds_passphrase structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_set_ewpa_mode(mlan_private * priv, mlan_ds_passphrase * psec_pp)
+{
+ ENTER();
+
+ if ((psec_pp->psk_type == MLAN_PSK_PASSPHRASE &&
+ psec_pp->psk.passphrase.passphrase_len > 0) ||
+ (psec_pp->psk_type == MLAN_PSK_PMK))
+ priv->sec_info.ewpa_enabled = MTRUE;
+ else
+ priv->sec_info.ewpa_enabled = MFALSE;
+
+ PRINTM(MINFO, "Set ewpa mode = %d\n", priv->sec_info.ewpa_enabled);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_find_bss(mlan_private * pmpriv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ int i = 0;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ if (memcmp
+ (pmadapter, &bss->param.ssid_bssid.bssid, zero_mac, sizeof(zero_mac))) {
+ if (bss->param.ssid_bssid.ssid.ssid_len) /* ssid & bssid */
+ i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ else
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ memcpy(pmadapter, mac, &bss->param.ssid_bssid.bssid, sizeof(mac));
+ PRINTM(MERROR, "Can not find bssid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &bss->param.ssid_bssid.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+ /* index in bss list,start from 1 */
+ bss->param.ssid_bssid.idx = i + 1;
+ } else if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid, MNULL,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ PRINTM(MERROR, "Can not find ssid %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, (t_u8 *) & bss->param.ssid_bssid.bssid,
+ (t_u8 *) & pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
+ /* index in bss list, start from 1 */
+ bss->param.ssid_bssid.idx = i + 1;
+ } else {
+ ret = wlan_find_best_network(pmpriv, &bss->param.ssid_bssid);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN station ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_ops_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ status = wlan_scan_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_BSS:
+ status = wlan_bss_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ status = wlan_radio_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ status = wlan_snmp_mib_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_GET_INFO:
+ status = wlan_get_info_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ status = wlan_sec_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ status = wlan_rate_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_POWER_CFG:
+ status = wlan_power_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ status = wlan_pm_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WMM_CFG:
+ status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WPS_CFG:
+ status = wlan_wps_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ status = wlan_11d_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_REG_MEM:
+ status = wlan_reg_mem_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ status = wlan_misc_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ status = wlan_11h_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
new file mode 100644
index 000000000000..5e5c68e2a108
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
@@ -0,0 +1,289 @@
+/** @file mlan_sta_rx.c
+ *
+ * @brief This file contains the handling of RX in MLAN
+ * module.
+ *
+ * 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/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Ethernet II header */
+typedef struct
+{
+ /** Ethernet II header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header length */
+ t_u16 ethertype;
+
+} EthII_Hdr_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ RxPacketHdr_t *prx_pkt;
+ RxPD *prx_pd;
+ int hdr_chop;
+ EthII_Hdr_t *peth_hdr;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ t_u8 snap_oui_802_h[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+ t_u8 appletalk_aarp_type[2] = { 0x80, 0xf3 };
+ t_u8 ipx_snap_type[2] = { 0x81, 0x37 };
+
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+/** Small debug type */
+#define DBG_TYPE_SMALL 2
+/** Size of debugging structure */
+#define SIZE_OF_DBG_STRUCT 4
+ if (prx_pd->rx_pkt_type == PKT_TYPE_DEBUG) {
+ t_u8 dbgType;
+ dbgType = *(t_u8 *) & prx_pkt->eth803_hdr;
+ if (dbgType == DBG_TYPE_SMALL) {
+ PRINTM(MFW_D, "\n");
+ DBG_HEXDUMP(MFW_D, "FWDBG",
+ (t_s8 *) ((t_u8 *) & prx_pkt->eth803_hdr +
+ SIZE_OF_DBG_STRUCT), prx_pd->rx_pkt_length);
+ PRINTM(MFW_D, "FWDBG::\n");
+ }
+ goto done;
+ }
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ HEXDUMP("RX Data: Dest", prx_pkt->eth803_hdr.dest_addr,
+ sizeof(prx_pkt->eth803_hdr.dest_addr));
+ HEXDUMP("RX Data: Src", prx_pkt->eth803_hdr.src_addr,
+ sizeof(prx_pkt->eth803_hdr.src_addr));
+
+ if ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ snap_oui_802_h, sizeof(snap_oui_802_h)) == 0) ||
+ ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ appletalk_aarp_type, sizeof(appletalk_aarp_type)) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ ipx_snap_type, sizeof(ipx_snap_type)))) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type (ethertype).
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ * To create the Ethernet II, just move the src, dst address right
+ * before the snap_type.
+ */
+ peth_hdr = (EthII_Hdr_t *)
+ ((t_u8 *) & prx_pkt->eth803_hdr
+ + sizeof(prx_pkt->eth803_hdr) + sizeof(prx_pkt->rfc1042_hdr)
+ - sizeof(prx_pkt->eth803_hdr.dest_addr)
+ - sizeof(prx_pkt->eth803_hdr.src_addr)
+ - sizeof(prx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy(pmadapter, peth_hdr->src_addr, prx_pkt->eth803_hdr.src_addr,
+ sizeof(peth_hdr->src_addr));
+ memcpy(pmadapter, peth_hdr->dest_addr, prx_pkt->eth803_hdr.dest_addr,
+ sizeof(peth_hdr->dest_addr));
+
+ /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
+ that was removed. */
+ hdr_chop = (t_u32) ((t_ptr) peth_hdr - (t_ptr) prx_pd);
+ } else {
+ HEXDUMP("RX Data: LLC/SNAP",
+ (t_u8 *) & prx_pkt->rfc1042_hdr, sizeof(prx_pkt->rfc1042_hdr));
+
+ /* Chop off the RxPD */
+ hdr_chop = (t_u32) ((t_ptr) & prx_pkt->eth803_hdr - (t_ptr) prx_pd);
+ }
+
+ /* Chop off the leading header bytes so the it points to the start of
+ either the reconstructed EthII frame or the 802.2/llc/snap frame */
+ pmbuf->data_len -= hdr_chop;
+ pmbuf->data_offset += hdr_chop;
+ pmbuf->pparent = MNULL;
+
+ DBG_HEXDUMP(MDAT_D, "RxPD", (t_u8 *) prx_pd,
+ MIN(sizeof(RxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "Rx Payload", ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ priv->rxpd_rate = prx_pd->rx_rate;
+
+ priv->rxpd_htinfo = prx_pd->ht_info;
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ PRINTM(MERROR, "STA Rx Error: moal_recv_packet returned error\n");
+ }
+ done:
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_rx_packet(IN t_void * adapter, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ endian_convert_RxPD(prx_pd);
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) >
+ (t_u16) pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n", pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to forwarded to app as an
+ event */
+ pmgmt_pkt_hdr =
+ (wlan_mgmt_pkt *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+ pmgmt_pkt_hdr->frm_len = wlan_le16_to_cpu(pmgmt_pkt_hdr->frm_len);
+
+ if ((pmgmt_pkt_hdr->wlan_header.frm_ctl
+ & IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *) & pmgmt_pkt_hdr->
+ wlan_header,
+ pmgmt_pkt_hdr->frm_len +
+ sizeof(wlan_mgmt_pkt)
+ - sizeof(pmgmt_pkt_hdr->frm_len));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+
+ /*
+ * If the packet is not an unicast packet then send the packet
+ * directly to os. Don't pass thru rx reordering
+ */
+ if (!IS_11N_ENABLED(priv) ||
+ memcmp(priv->adapter, priv->curr_addr, prx_pkt->eth803_hdr.dest_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+
+ if (queuing_ra_based(priv)) {
+ memcpy(pmadapter, ta, prx_pkt->eth803_hdr.src_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ } else {
+ if ((rx_pkt_type != PKT_TYPE_BAR) && (prx_pd->priority < MAX_NUM_TID))
+ priv->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ memcpy(pmadapter, ta,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+
+ /* Reorder and send to OS */
+ if ((ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num,
+ prx_pd->priority, ta,
+ (t_u8) prx_pd->rx_pkt_type,
+ (void *) pmbuf)) ||
+ (rx_pkt_type == PKT_TYPE_BAR)
+ ) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ done:
+
+ LEAVE();
+ return (ret);
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
new file mode 100644
index 000000000000..2258853a4089
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
@@ -0,0 +1,277 @@
+/** @file mlan_sta_tx.c
+ *
+ * @brief This file contains the handling of data packet
+ * transmission in MLAN module.
+ *
+ * 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/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_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function fill the txpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *
+wlan_ops_sta_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf)
+{
+ mlan_private *pmpriv = (mlan_private *) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ TxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+
+ ENTER();
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "STA Tx Error: Invalid packet length: %d\n",
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ memcpy(pmpriv->adapter, &pkt_type, pmbuf->pbuf + pmbuf->data_offset,
+ sizeof(pkt_type));
+ memcpy(pmpriv->adapter, &tx_control,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ sizeof(tx_control));
+ pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
+ pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
+ }
+
+ if (pmbuf->data_offset < (sizeof(TxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT)) {
+ PRINTM(MERROR, "not enough space for TxPD: %d\n", pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr =
+ pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) - INTF_HEADER_LEN;
+ head_ptr = (t_u8 *) ((t_ptr) head_ptr & ~((t_ptr) (DMA_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN);
+ memset(pmadapter, plocal_tx_pd, 0, sizeof(TxPD));
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
+ plocal_tx_pd->bss_type = pmpriv->bss_type;
+
+ plocal_tx_pd->tx_pkt_length = (t_u16) pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8) pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority < NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control
+ = pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+ if (pmadapter->pps_uapsd_mode) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ pmadapter->tx_lock_flag = MTRUE;
+ plocal_tx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset =
+ (t_u16) ((t_ptr) pmbuf->pbuf + pmbuf->data_offset -
+ (t_ptr) plocal_tx_pd);
+
+ if (!plocal_tx_pd->tx_control) {
+ /* TxCtrl set by user or default */
+ plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
+ }
+
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ plocal_tx_pd->tx_pkt_type = (t_u16) pkt_type;
+ plocal_tx_pd->tx_control = tx_control;
+ }
+
+ endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = (t_u32) (head_ptr - pmbuf->pbuf);
+ pmbuf->data_len -= pmbuf->data_offset;
+
+ done:
+ LEAVE();
+ return head_ptr;
+}
+
+/**
+ * @brief This function tells firmware to send a NULL data packet.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param flags Transmit Pkt Flags
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure
+ */
+mlan_status
+wlan_send_null_packet(pmlan_private priv, t_u8 flags)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ TxPD *ptx_pd;
+/* sizeof(TxPD) + Interface specific header */
+#define NULL_PACKET_HDR 256
+ t_u32 data_len = NULL_PACKET_HDR;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 *ptr;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+
+ ENTER();
+
+ if (pmadapter->surprise_removed == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->data_sent == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0, MTRUE);
+ if (!pmbuf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmadapter, pmbuf->pbuf, 0, data_len);
+ pmbuf->bss_index = priv->bss_index;
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ ptr = pmbuf->pbuf + pmbuf->data_offset;
+ pmbuf->data_len = sizeof(TxPD) + INTF_HEADER_LEN;
+ ptx_pd = (TxPD *) (ptr + INTF_HEADER_LEN);
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+ ptx_pd->flags = flags;
+ ptx_pd->priority = WMM_HIGHEST_PRIORITY;
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ /* Set the BSS number to TxPD */
+ ptx_pd->bss_num = GET_BSS_NUM(priv);
+ ptx_pd->bss_type = priv->bss_type;
+
+ endian_convert_TxPD(ptx_pd);
+
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, MNULL);
+
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->data_sent = MTRUE;
+ /* Fall through FAILURE handling */
+ case MLAN_STATUS_FAILURE:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ goto done;
+ case MLAN_STATUS_SUCCESS:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n");
+ pmadapter->tx_lock_flag = MTRUE;
+ break;
+ case MLAN_STATUS_PENDING:
+ break;
+ default:
+ break;
+ }
+
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec);
+ DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if we need to send last packet indication.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8
+wlan_check_last_packet_indication(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 ret = MFALSE;
+ t_u8 prop_ps = MTRUE;
+
+ ENTER();
+
+ if (!pmadapter->sleep_period.period) {
+ LEAVE();
+ return ret;
+ }
+ if (wlan_bypass_tx_list_empty(pmadapter) && wlan_wmm_lists_empty(pmadapter)) {
+ if (((priv->curr_bss_params.wmm_uapsd_enabled == MTRUE) &&
+ priv->wmm_qosinfo) || prop_ps)
+
+ ret = MTRUE;
+ }
+ if (ret && !pmadapter->cmd_sent && !pmadapter->curr_cmd
+ && !IS_COMMAND_PENDING(pmadapter)) {
+ pmadapter->delay_null_pkt = MFALSE;
+ ret = MTRUE;
+ } else {
+ ret = MFALSE;
+ pmadapter->delay_null_pkt = MTRUE;
+ }
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_txrx.c b/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
new file mode 100644
index 000000000000..93dea9e284f8
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
@@ -0,0 +1,376 @@
+/**
+ * @file mlan_txrx.c
+ *
+ * @brief This file contains the handling of TX/RX in MLAN
+ *
+ * Copyright (C) 2009-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:
+ 05/11/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ RxPD *prx_pd;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Get the BSS number from RxPD, get corresponding priv */
+ priv =
+ wlan_get_priv_by_id(pmadapter, prx_pd->bss_num & BSS_NUM_MASK,
+ prx_pd->bss_type);
+ if (!priv)
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmbuf->bss_index = priv->bss_index;
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data <= FW\n", sec, usec);
+ ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to device
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ * @param tx_param A pointer to mlan_tx_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure
+ */
+mlan_status
+wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param * tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 *head_ptr = MNULL;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+#ifdef STA_SUPPORT
+ TxPD *plocal_tx_pd = MNULL;
+#endif
+
+ ENTER();
+
+ head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf);
+ if (!head_ptr) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN);
+#endif
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param);
+ done:
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) {
+ pmadapter->tx_lock_flag = MFALSE;
+ plocal_tx_pd->flags = 0;
+ }
+#endif
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN,
+ MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+ break;
+ case MLAN_STATUS_SUCCESS:
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN,
+ MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet send completion handling
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_write_data_complete(IN pmlan_adapter pmadapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmadapter && pmbuf);
+
+ pcb = &pmadapter->callbacks;
+ if ((pmbuf->buf_type == MLAN_BUF_TYPE_DATA) ||
+ (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)) {
+ PRINTM(MINFO, "wlan_write_data_complete: DATA %p\n", pmbuf);
+ if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF) {
+ /* pmbuf was allocated by MOAL */
+ pcb->moal_send_packet_complete(pmadapter->pmoal_handle,
+ pmbuf, status);
+ } else {
+ if (pmbuf->flags & MLAN_BUF_FLAG_BRIDGE_BUF) {
+ pmadapter->pending_bridge_pkts--;
+ }
+ /* pmbuf was allocated by MLAN */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_recv_packet_complete(IN pmlan_adapter pmadapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmp;
+ pmlan_callbacks pcb;
+ pmlan_buffer pmbuf_parent;
+
+ ENTER();
+
+ MASSERT(pmadapter && pmbuf);
+ pcb = &pmadapter->callbacks;
+ MASSERT(pmbuf->bss_index < pmadapter->priv_num);
+
+ pmp = pmadapter->priv[pmbuf->bss_index];
+
+ if (pmbuf->pparent) {
+ pmbuf_parent = pmbuf->pparent;
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmp->rx_pkt_lock);
+ --pmbuf_parent->use_count;
+ if (!pmbuf_parent->use_count) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmp->rx_pkt_lock);
+ wlan_free_mlan_buffer(pmadapter, pmbuf_parent);
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmp->rx_pkt_lock);
+ }
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add packet to Bypass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_add_buf_bypass_txqueue(mlan_adapter * pmadapter, pmlan_buffer pmbuf)
+{
+ ENTER();
+
+ if (pmbuf->buf_type != MLAN_BUF_TYPE_RAW_DATA) {
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ }
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->bypass_txq,
+ (pmlan_linked_list) pmbuf,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ LEAVE();
+}
+
+/**
+ * @brief Check if packets are available in Bypass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+INLINE t_u8
+wlan_bypass_tx_list_empty(mlan_adapter * pmadapter)
+{
+ t_u8 q_empty = MTRUE;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+
+ q_empty = (util_peek_list(pmadapter->pmoal_handle, &pmadapter->bypass_txq,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)) ? MFALSE : MTRUE;
+
+ LEAVE();
+ return q_empty;
+}
+
+/**
+ * @brief Clean up the By-pass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_cleanup_bypass_txq(mlan_adapter * pmadapter)
+{
+ pmlan_buffer pmbuf;
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->bypass_txq.plock);
+
+ while ((pmbuf =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq, MNULL,
+ MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->bypass_txq,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ }
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->bypass_txq.plock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Transmit the By-passed packet awaiting in by-pass queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_process_bypass_tx(pmlan_adapter pmadapter)
+{
+ pmlan_buffer pmbuf;
+ mlan_tx_param tx_param;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ PRINTM(MINFO, "Dequeuing bypassed packet %p\n", pmbuf);
+ /* XXX: nex_pkt_len ??? */
+ tx_param.next_pkt_len = 0;
+ status =
+ wlan_process_tx(pmadapter->priv[pmbuf->bss_index], pmbuf,
+ &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /* Queue the packet again so that it will be TX'ed later */
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq,
+ (pmlan_linked_list) pmbuf,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+ } else {
+ PRINTM(MINFO, "Nothing to send\n");
+ }
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap.h b/drivers/net/wireless/sd8797/mlan/mlan_uap.h
new file mode 100644
index 000000000000..c2d2800f1a2d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap.h
@@ -0,0 +1,104 @@
+/** @file mlan_uap.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of uap functionalities
+ *
+ * Copyright (C) 2009-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:
+ 02/05/2009: initial version
+********************************************************/
+
+#ifndef _MLAN_UAP_H_
+#define _MLAN_UAP_H_
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert TxPD to little endian format from CPU format */
+#define uap_endian_convert_TxPD(x) \
+ { \
+ (x)->tx_pkt_length = wlan_cpu_to_le16((x)->tx_pkt_length); \
+ (x)->tx_pkt_offset = wlan_cpu_to_le16((x)->tx_pkt_offset); \
+ (x)->tx_pkt_type = wlan_cpu_to_le16((x)->tx_pkt_type); \
+ (x)->tx_control = wlan_cpu_to_le32((x)->tx_control); \
+ }
+
+/** Convert RxPD from little endian format to CPU format */
+#define uap_endian_convert_RxPD(x) \
+ { \
+ (x)->rx_pkt_length = wlan_le16_to_cpu((x)->rx_pkt_length); \
+ (x)->rx_pkt_offset = wlan_le16_to_cpu((x)->rx_pkt_offset); \
+ (x)->rx_pkt_type = wlan_le16_to_cpu((x)->rx_pkt_type); \
+ (x)->seq_num = wlan_le16_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert TxPD to little endian format from CPU format */
+#define uap_endian_convert_TxPD(x) do {} while (0)
+/** Convert RxPD from little endian format to CPU format */
+#define uap_endian_convert_RxPD(x) do {} while (0)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** Band config 5GHz */
+#define UAP_BAND_CONFIG_5GHZ 0x01
+
+/** Packet forwarding to be done by FW or host */
+#define PKT_FWD_FW_BIT 0x01
+/** Intra-BSS broadcast packet forwarding allow bit */
+#define PKT_FWD_INTRA_BCAST 0x02
+/** Intra-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTRA_UCAST 0x04
+/** Inter-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTER_UCAST 0x08
+/** Intra-BSS unicast packet */
+#define PKT_INTRA_UCAST 0x01
+/** Inter-BSS unicast packet */
+#define PKT_INTER_UCAST 0x02
+/** Enable Host PKT forwarding */
+#define PKT_FWD_ENABLE_BIT 0x01
+
+mlan_status wlan_uap_get_channel(IN pmlan_private pmpriv);
+
+mlan_status wlan_uap_set_channel(IN pmlan_private pmpriv,
+ IN t_u8 uap_band_cfg, IN t_u8 channel);
+
+mlan_status wlan_uap_get_beacon_dtim(IN pmlan_private pmpriv);
+
+mlan_status wlan_ops_uap_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_ops_uap_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf,
+ IN t_void * pcmd_buf);
+
+mlan_status wlan_ops_uap_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf,
+ IN t_void * pioctl);
+
+mlan_status wlan_ops_uap_process_rx_packet(IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+
+mlan_status wlan_ops_uap_process_event(IN t_void * priv);
+
+t_void *wlan_ops_uap_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf);
+
+mlan_status wlan_ops_uap_init_cmd(IN t_void * priv, IN t_u8 first_bss);
+
+#endif /* _MLAN_UAP_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
new file mode 100644
index 000000000000..7d7d5510433c
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
@@ -0,0 +1,3021 @@
+/** @file mlan_uap_cmdevent.c
+ *
+ * @brief This file contains the handling of AP mode command and event
+ *
+ * Copyright (C) 2009-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:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_sdio.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+static void
+uap_process_cmdresp_error(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n", resp->command,
+ resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = resp->result;
+ /*
+ * Handling errors here
+ */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_uap_cmd_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN hs_config_param * pdata_buf)
+{
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &cmd->params.opt_hs_cfg;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+ cmd->size =
+ wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_HS_CFG_ENH));
+
+ if (pdata_buf == MNULL) {
+ phs_cfg->action = wlan_cpu_to_le16(HS_ACTIVATE);
+ phs_cfg->params.hs_activate.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
+ } else {
+ phs_cfg->action = wlan_cpu_to_le16(HS_CONFIGURE);
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->gap;
+ PRINTM(MCMND, "HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Tx data pause
+ *
+ * @param pmpriv 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
+ */
+static mlan_status
+wlan_uap_cmd_txdatapause(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_CMD_TX_DATA_PAUSE *pause_cmd =
+ (HostCmd_DS_CMD_TX_DATA_PAUSE *) & cmd->params.tx_data_pause;
+ mlan_ds_misc_tx_datapause *data_pause =
+ (mlan_ds_misc_tx_datapause *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CFG_TX_DATA_PAUSE);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_TX_DATA_PAUSE) + S_DS_GEN);
+ pause_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pause_cmd->enable_tx_pause = (t_u8) data_pause->tx_pause;
+ pause_cmd->pause_tx_count = (t_u8) data_pause->tx_buf_cnt;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Tx data pause
+ *
+ * @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
+ */
+static mlan_status
+wlan_uap_ret_txdatapause(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_CMD_TX_DATA_PAUSE *pause_cmd =
+ (HostCmd_DS_CMD_TX_DATA_PAUSE *) & resp->params.tx_data_pause;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc_cfg->param.tx_datapause.tx_pause = pause_cmd->enable_tx_pause;
+ misc_cfg->param.tx_datapause.tx_buf_cnt = pause_cmd->pause_tx_count;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will process tx pause event
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void
+wlan_process_tx_pause_event(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - sizeof(t_u32);
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *) (pevent->pbuf + pevent->data_offset +
+ sizeof(t_u32));
+ MrvlIEtypes_tx_pause_t *tx_pause_tlv;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_TX_PAUSE) {
+ tx_pause_tlv = (MrvlIEtypes_tx_pause_t *) tlv;
+ PRINTM(MCMND,
+ "TxPause: %02x:%02x:%02x:%02x:%02x:%02x pause=%d, pkts=%d\n",
+ tx_pause_tlv->peermac[0], tx_pause_tlv->peermac[1],
+ tx_pause_tlv->peermac[2], tx_pause_tlv->peermac[3],
+ tx_pause_tlv->peermac[4], tx_pause_tlv->peermac[5],
+ tx_pause_tlv->tx_pause, tx_pause_tlv->pkt_cnt);
+ if ((sta_ptr = wlan_get_station_entry(priv, tx_pause_tlv->peermac))) {
+ if (sta_ptr->tx_pause != tx_pause_tlv->tx_pause) {
+ sta_ptr->tx_pause = tx_pause_tlv->tx_pause;
+ wlan_updata_ralist_tx_pause(priv, tx_pause_tlv->peermac,
+ tx_pause_tlv->tx_pause);
+ }
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares command for config uap settings
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_uap_cmd_ap_config(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN pmlan_ioctl_req pioctl_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & cmd->params.sys_config;
+ t_u8 *tlv = MNULL;
+ MrvlIEtypes_MacAddr_t *tlv_mac = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_beacon_period = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtim_period = MNULL;
+ MrvlIEtypes_RatesParamSet_t *tlv_rates = MNULL;
+ MrvlIEtypes_tx_rate_t *tlv_txrate = MNULL;
+ MrvlIEtypes_mcbc_rate_t *tlv_mcbc_rate = MNULL;
+ MrvlIEtypes_tx_power_t *tlv_tx_power = MNULL;
+ MrvlIEtypes_bcast_ssid_t *tlv_bcast_ssid = MNULL;
+ MrvlIEtypes_antenna_mode_t *tlv_antenna = MNULL;
+ MrvlIEtypes_pkt_forward_t *tlv_pkt_forward = MNULL;
+ MrvlIEtypes_max_sta_count_t *tlv_sta_count = MNULL;
+ MrvlIEtypes_sta_ageout_t *tlv_sta_ageout = MNULL;
+ MrvlIEtypes_ps_sta_ageout_t *tlv_ps_sta_ageout = MNULL;
+ MrvlIEtypes_rts_threshold_t *tlv_rts_threshold = MNULL;
+ MrvlIEtypes_frag_threshold_t *tlv_frag_threshold = MNULL;
+ MrvlIEtypes_retry_limit_t *tlv_retry_limit = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_timeout_t *tlv_pairwise_timeout = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_retries_t *tlv_pairwise_retries = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_timeout_t *tlv_groupwise_timeout = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_retries_t *tlv_groupwise_retries = MNULL;
+ MrvlIEtypes_mgmt_ie_passthru_t *tlv_mgmt_ie_passthru = MNULL;
+ MrvlIEtypes_2040_coex_enable_t *tlv_2040_coex_enable = MNULL;
+ MrvlIEtypes_mac_filter_t *tlv_mac_filter = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_chan_band = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_auth_type_t *tlv_auth_type = MNULL;
+ MrvlIEtypes_encrypt_protocol_t *tlv_encrypt_protocol = MNULL;
+ MrvlIEtypes_akmp_t *tlv_akmp = MNULL;
+ MrvlIEtypes_pwk_cipher_t *tlv_pwk_cipher = MNULL;
+ MrvlIEtypes_gwk_cipher_t *tlv_gwk_cipher = MNULL;
+ MrvlIEtypes_rsn_replay_prot_t *tlv_rsn_prot = MNULL;
+ MrvlIEtypes_passphrase_t *tlv_passphrase = MNULL;
+ MrvlIEtypes_group_rekey_time_t *tlv_rekey_time = MNULL;
+ MrvlIEtypes_wep_key_t *tlv_wep_key = MNULL;
+ MrvlIETypes_HTCap_t *tlv_htcap = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+ t_u32 cmd_size = 0;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u16 i;
+ t_u16 ac;
+
+ ENTER();
+ if (pioctl_buf == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
+ sys_config->action = wlan_cpu_to_le16(cmd_action);
+ cmd_size = sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN;
+
+ tlv = (t_u8 *) sys_config->tlv_buffer;
+ if (memcmp
+ (pmpriv->adapter, zero_mac, &bss->param.bss_config.mac_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ tlv_mac = (MrvlIEtypes_MacAddr_t *) tlv;
+ tlv_mac->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ tlv_mac->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmpriv->adapter, tlv_mac->mac, &bss->param.bss_config.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ cmd_size += sizeof(MrvlIEtypes_MacAddr_t);
+ tlv += sizeof(MrvlIEtypes_MacAddr_t);
+ }
+
+ if (bss->param.bss_config.ssid.ssid_len) {
+ tlv_ssid = (MrvlIEtypes_SsIdParamSet_t *) tlv;
+ tlv_ssid->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ tlv_ssid->header.len =
+ wlan_cpu_to_le16((t_u16) bss->param.bss_config.ssid.ssid_len);
+ memcpy(pmpriv->adapter, tlv_ssid->ssid, bss->param.bss_config.ssid.ssid,
+ bss->param.bss_config.ssid.ssid_len);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + bss->param.bss_config.ssid.ssid_len;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + bss->param.bss_config.ssid.ssid_len;
+ }
+
+ if ((bss->param.bss_config.beacon_period >= MIN_BEACON_PERIOD) &&
+ (bss->param.bss_config.beacon_period <= MAX_BEACON_PERIOD)) {
+ tlv_beacon_period = (MrvlIEtypes_beacon_period_t *) tlv;
+ tlv_beacon_period->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
+ tlv_beacon_period->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_beacon_period->beacon_period =
+ wlan_cpu_to_le16(bss->param.bss_config.beacon_period);
+ cmd_size += sizeof(MrvlIEtypes_beacon_period_t);
+ tlv += sizeof(MrvlIEtypes_beacon_period_t);
+ }
+
+ if ((bss->param.bss_config.dtim_period >= MIN_DTIM_PERIOD) &&
+ (bss->param.bss_config.dtim_period <= MAX_DTIM_PERIOD)) {
+ tlv_dtim_period = (MrvlIEtypes_dtim_period_t *) tlv;
+ tlv_dtim_period->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+ tlv_dtim_period->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_dtim_period->dtim_period = bss->param.bss_config.dtim_period;
+ cmd_size += sizeof(MrvlIEtypes_dtim_period_t);
+ tlv += sizeof(MrvlIEtypes_dtim_period_t);
+ }
+
+ if (bss->param.bss_config.rates[0]) {
+ tlv_rates = (MrvlIEtypes_RatesParamSet_t *) tlv;
+ tlv_rates->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ for (i = 0; i < MAX_DATA_RATES && bss->param.bss_config.rates[i]; i++) {
+ tlv_rates->rates[i] = bss->param.bss_config.rates[i];
+ }
+ tlv_rates->header.len = wlan_cpu_to_le16(i);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + i;
+ tlv += sizeof(MrvlIEtypesHeader_t) + i;
+ }
+
+ if (bss->param.bss_config.tx_data_rate <= DATA_RATE_54M) {
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *) tlv;
+ tlv_txrate->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_TX_DATA_RATE);
+ tlv_txrate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_txrate->tx_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.tx_data_rate);
+ cmd_size += sizeof(MrvlIEtypes_tx_rate_t);
+ tlv += sizeof(MrvlIEtypes_tx_rate_t);
+ }
+
+ if (bss->param.bss_config.mcbc_data_rate <= DATA_RATE_54M) {
+ tlv_mcbc_rate = (MrvlIEtypes_mcbc_rate_t *) tlv;
+ tlv_mcbc_rate->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MCBC_DATA_RATE);
+ tlv_mcbc_rate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_mcbc_rate->mcbc_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.mcbc_data_rate);
+ cmd_size += sizeof(MrvlIEtypes_mcbc_rate_t);
+ tlv += sizeof(MrvlIEtypes_mcbc_rate_t);
+ }
+
+ if (bss->param.bss_config.tx_power_level <= MAX_TX_POWER) {
+ tlv_tx_power = (MrvlIEtypes_tx_power_t *) tlv;
+ tlv_tx_power->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_TX_POWER);
+ tlv_tx_power->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_tx_power->tx_power = bss->param.bss_config.tx_power_level;
+ cmd_size += sizeof(MrvlIEtypes_tx_power_t);
+ tlv += sizeof(MrvlIEtypes_tx_power_t);
+ }
+
+ if (bss->param.bss_config.bcast_ssid_ctl <= MTRUE) {
+ tlv_bcast_ssid = (MrvlIEtypes_bcast_ssid_t *) tlv;
+ tlv_bcast_ssid->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID_CTL);
+ tlv_bcast_ssid->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_bcast_ssid->bcast_ssid_ctl = bss->param.bss_config.bcast_ssid_ctl;
+ cmd_size += sizeof(MrvlIEtypes_bcast_ssid_t);
+ tlv += sizeof(MrvlIEtypes_bcast_ssid_t);
+ }
+
+ if ((bss->param.bss_config.tx_antenna == ANTENNA_MODE_A) ||
+ (bss->param.bss_config.tx_antenna == ANTENNA_MODE_B)) {
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *) tlv;
+ tlv_antenna->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_ANTENNA_CTL);
+ tlv_antenna->header.len = wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_antenna->which_antenna = TX_ANTENNA;
+ tlv_antenna->antenna_mode = bss->param.bss_config.tx_antenna;
+ cmd_size += sizeof(MrvlIEtypes_antenna_mode_t);
+ tlv += sizeof(MrvlIEtypes_antenna_mode_t);
+ }
+
+ if ((bss->param.bss_config.rx_antenna == ANTENNA_MODE_A) ||
+ (bss->param.bss_config.rx_antenna == ANTENNA_MODE_B)) {
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *) tlv;
+ tlv_antenna->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_ANTENNA_CTL);
+ tlv_antenna->header.len = wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_antenna->which_antenna = RX_ANTENNA;
+ tlv_antenna->antenna_mode = bss->param.bss_config.rx_antenna;
+ cmd_size += sizeof(MrvlIEtypes_antenna_mode_t);
+ tlv += sizeof(MrvlIEtypes_antenna_mode_t);
+ }
+
+ if (bss->param.bss_config.pkt_forward_ctl <= MAX_PKT_FWD_CTRL) {
+ tlv_pkt_forward = (MrvlIEtypes_pkt_forward_t *) tlv;
+ tlv_pkt_forward->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PKT_FWD_CTL);
+ tlv_pkt_forward->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_pkt_forward->pkt_forward_ctl =
+ bss->param.bss_config.pkt_forward_ctl;
+ cmd_size += sizeof(MrvlIEtypes_pkt_forward_t);
+ tlv += sizeof(MrvlIEtypes_pkt_forward_t);
+ }
+
+ if (bss->param.bss_config.max_sta_count <= MAX_STA_COUNT) {
+ tlv_sta_count = (MrvlIEtypes_max_sta_count_t *) tlv;
+ tlv_sta_count->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAX_STA_CNT);
+ tlv_sta_count->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_sta_count->max_sta_count =
+ wlan_cpu_to_le16(bss->param.bss_config.max_sta_count);
+ cmd_size += sizeof(MrvlIEtypes_max_sta_count_t);
+ tlv += sizeof(MrvlIEtypes_max_sta_count_t);
+ }
+
+ if (((bss->param.bss_config.sta_ageout_timer >= MIN_STAGE_OUT_TIME) &&
+ (bss->param.bss_config.sta_ageout_timer <= MAX_STAGE_OUT_TIME)) ||
+ (bss->param.bss_config.sta_ageout_timer == 0)) {
+ tlv_sta_ageout = (MrvlIEtypes_sta_ageout_t *) tlv;
+ tlv_sta_ageout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_STA_AGEOUT_TIMER);
+ tlv_sta_ageout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_sta_ageout->sta_ageout_timer =
+ wlan_cpu_to_le32(bss->param.bss_config.sta_ageout_timer);
+ cmd_size += sizeof(MrvlIEtypes_sta_ageout_t);
+ tlv += sizeof(MrvlIEtypes_sta_ageout_t);
+ }
+
+ if (((bss->param.bss_config.ps_sta_ageout_timer >= MIN_STAGE_OUT_TIME) &&
+ (bss->param.bss_config.ps_sta_ageout_timer <= MAX_STAGE_OUT_TIME)) ||
+ (bss->param.bss_config.ps_sta_ageout_timer == 0)) {
+ tlv_ps_sta_ageout = (MrvlIEtypes_ps_sta_ageout_t *) tlv;
+ tlv_ps_sta_ageout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER);
+ tlv_ps_sta_ageout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_ps_sta_ageout->ps_sta_ageout_timer =
+ wlan_cpu_to_le32(bss->param.bss_config.ps_sta_ageout_timer);
+ cmd_size += sizeof(MrvlIEtypes_ps_sta_ageout_t);
+ tlv += sizeof(MrvlIEtypes_ps_sta_ageout_t);
+ }
+ if (bss->param.bss_config.rts_threshold <= MAX_RTS_THRESHOLD) {
+ tlv_rts_threshold = (MrvlIEtypes_rts_threshold_t *) tlv;
+ tlv_rts_threshold->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
+ tlv_rts_threshold->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_rts_threshold->rts_threshold =
+ wlan_cpu_to_le16(bss->param.bss_config.rts_threshold);
+ cmd_size += sizeof(MrvlIEtypes_rts_threshold_t);
+ tlv += sizeof(MrvlIEtypes_rts_threshold_t);
+ }
+
+ if ((bss->param.bss_config.frag_threshold >= MIN_FRAG_THRESHOLD) &&
+ (bss->param.bss_config.frag_threshold <= MAX_FRAG_THRESHOLD)) {
+ tlv_frag_threshold = (MrvlIEtypes_frag_threshold_t *) tlv;
+ tlv_frag_threshold->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
+ tlv_frag_threshold->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_frag_threshold->frag_threshold =
+ wlan_cpu_to_le16(bss->param.bss_config.frag_threshold);
+ cmd_size += sizeof(MrvlIEtypes_frag_threshold_t);
+ tlv += sizeof(MrvlIEtypes_frag_threshold_t);
+ }
+
+ if (bss->param.bss_config.retry_limit <= MAX_RETRY_LIMIT) {
+ tlv_retry_limit = (MrvlIEtypes_retry_limit_t *) tlv;
+ tlv_retry_limit->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
+ tlv_retry_limit->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_retry_limit->retry_limit = (t_u8) bss->param.bss_config.retry_limit;
+ cmd_size += sizeof(MrvlIEtypes_retry_limit_t);
+ tlv += sizeof(MrvlIEtypes_retry_limit_t);
+ }
+
+ if (bss->param.bss_config.pairwise_update_timeout < (MAX_VALID_DWORD)) {
+ tlv_pairwise_timeout = (MrvlIEtypes_eapol_pwk_hsk_timeout_t *) tlv;
+ tlv_pairwise_timeout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT);
+ tlv_pairwise_timeout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_pairwise_timeout->pairwise_update_timeout =
+ wlan_cpu_to_le32(bss->param.bss_config.pairwise_update_timeout);
+ cmd_size += sizeof(MrvlIEtypes_eapol_pwk_hsk_timeout_t);
+ tlv += sizeof(MrvlIEtypes_eapol_pwk_hsk_timeout_t);
+ }
+
+ if (bss->param.bss_config.pwk_retries < (MAX_VALID_DWORD)) {
+ tlv_pairwise_retries = (MrvlIEtypes_eapol_pwk_hsk_retries_t *) tlv;
+ tlv_pairwise_retries->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES);
+ tlv_pairwise_retries->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_pairwise_retries->pwk_retries =
+ wlan_cpu_to_le32(bss->param.bss_config.pwk_retries);
+ cmd_size += sizeof(MrvlIEtypes_eapol_pwk_hsk_retries_t);
+ tlv += sizeof(MrvlIEtypes_eapol_pwk_hsk_retries_t);
+ }
+
+ if (bss->param.bss_config.groupwise_update_timeout < (MAX_VALID_DWORD)) {
+ tlv_groupwise_timeout = (MrvlIEtypes_eapol_gwk_hsk_timeout_t *) tlv;
+ tlv_groupwise_timeout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT);
+ tlv_groupwise_timeout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_groupwise_timeout->groupwise_update_timeout =
+ wlan_cpu_to_le32(bss->param.bss_config.groupwise_update_timeout);
+ cmd_size += sizeof(MrvlIEtypes_eapol_gwk_hsk_timeout_t);
+ tlv += sizeof(MrvlIEtypes_eapol_gwk_hsk_timeout_t);
+ }
+
+ if (bss->param.bss_config.gwk_retries < (MAX_VALID_DWORD)) {
+ tlv_groupwise_retries = (MrvlIEtypes_eapol_gwk_hsk_retries_t *) tlv;
+ tlv_groupwise_retries->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES);
+ tlv_groupwise_retries->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_groupwise_retries->gwk_retries =
+ wlan_cpu_to_le32(bss->param.bss_config.gwk_retries);
+ cmd_size += sizeof(MrvlIEtypes_eapol_gwk_hsk_retries_t);
+ tlv += sizeof(MrvlIEtypes_eapol_gwk_hsk_retries_t);
+ }
+
+ if ((bss->param.bss_config.filter.filter_mode <= MAC_FILTER_MODE_BLOCK_MAC)
+ && (bss->param.bss_config.filter.mac_count <= MAX_MAC_FILTER_NUM)) {
+ tlv_mac_filter = (MrvlIEtypes_mac_filter_t *) tlv;
+ tlv_mac_filter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_STA_MAC_ADDR_FILTER);
+ tlv_mac_filter->header.len =
+ wlan_cpu_to_le16(2 +
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count);
+ tlv_mac_filter->count = (t_u8) bss->param.bss_config.filter.mac_count;
+ tlv_mac_filter->filter_mode =
+ (t_u8) bss->param.bss_config.filter.filter_mode;
+ memcpy(pmpriv->adapter, tlv_mac_filter->mac_address,
+ (t_u8 *) bss->param.bss_config.filter.mac_list,
+ MLAN_MAC_ADDR_LENGTH * bss->param.bss_config.filter.mac_count);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ MLAN_MAC_ADDR_LENGTH * bss->param.bss_config.filter.mac_count;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ MLAN_MAC_ADDR_LENGTH * bss->param.bss_config.filter.mac_count;
+ }
+
+ if ((((bss->param.bss_config.band_cfg & BAND_CONFIG_ACS_MODE) ==
+ BAND_CONFIG_MANUAL) && (bss->param.bss_config.channel > 0) &&
+ (bss->param.bss_config.channel <= MLAN_MAX_CHANNEL)) ||
+ (bss->param.bss_config.band_cfg & BAND_CONFIG_ACS_MODE)) {
+ tlv_chan_band = (MrvlIEtypes_channel_band_t *) tlv;
+ tlv_chan_band->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ tlv_chan_band->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_chan_band->band_config = bss->param.bss_config.band_cfg;
+ tlv_chan_band->channel = bss->param.bss_config.channel;
+ cmd_size += sizeof(MrvlIEtypes_channel_band_t);
+ tlv += sizeof(MrvlIEtypes_channel_band_t);
+ }
+
+ if ((bss->param.bss_config.num_of_chan) &&
+ (bss->param.bss_config.num_of_chan <= MLAN_MAX_CHANNEL)) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ tlv_chan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16((t_u16)
+ (sizeof(ChanScanParamSet_t) *
+ bss->param.bss_config.num_of_chan));
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0; i < bss->param.bss_config.num_of_chan; i++) {
+ pscan_chan->chan_number =
+ bss->param.bss_config.chan_list[i].chan_number;
+ pscan_chan->radio_type =
+ bss->param.bss_config.chan_list[i].band_config_type;
+ pscan_chan++;
+ }
+ cmd_size += sizeof(tlv_chan_list->header) +
+ (sizeof(ChanScanParamSet_t) * bss->param.bss_config.num_of_chan);
+ tlv += sizeof(tlv_chan_list->header) +
+ (sizeof(ChanScanParamSet_t) * bss->param.bss_config.num_of_chan);
+ }
+
+ if ((bss->param.bss_config.auth_mode <= MLAN_AUTH_MODE_SHARED) ||
+ (bss->param.bss_config.auth_mode == MLAN_AUTH_MODE_AUTO)) {
+ tlv_auth_type = (MrvlIEtypes_auth_type_t *) tlv;
+ tlv_auth_type->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ tlv_auth_type->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_auth_type->auth_type = (t_u8) bss->param.bss_config.auth_mode;
+ cmd_size += sizeof(MrvlIEtypes_auth_type_t);
+ tlv += sizeof(MrvlIEtypes_auth_type_t);
+ }
+
+ if (bss->param.bss_config.protocol) {
+ tlv_encrypt_protocol = (MrvlIEtypes_encrypt_protocol_t *) tlv;
+ tlv_encrypt_protocol->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_ENCRYPT_PROTOCOL);
+ tlv_encrypt_protocol->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_encrypt_protocol->protocol =
+ wlan_cpu_to_le16(bss->param.bss_config.protocol);
+ cmd_size += sizeof(MrvlIEtypes_encrypt_protocol_t);
+ tlv += sizeof(MrvlIEtypes_encrypt_protocol_t);
+ }
+
+ if ((bss->param.bss_config.protocol & PROTOCOL_WPA) ||
+ (bss->param.bss_config.protocol & PROTOCOL_WPA2) ||
+ (bss->param.bss_config.protocol & PROTOCOL_EAP)) {
+ tlv_akmp = (MrvlIEtypes_akmp_t *) tlv;
+ tlv_akmp->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_AKMP);
+ tlv_akmp->key_mgmt = wlan_cpu_to_le16(bss->param.bss_config.key_mgmt);
+ tlv_akmp->header.len = sizeof(t_u16);
+ tlv_akmp->key_mgmt_operation =
+ wlan_cpu_to_le16(bss->param.bss_config.key_mgmt_operation);
+ tlv_akmp->header.len += sizeof(t_u16);
+ tlv_akmp->header.len = wlan_cpu_to_le16(tlv_akmp->header.len);
+ cmd_size += sizeof(MrvlIEtypes_akmp_t);
+ tlv += sizeof(MrvlIEtypes_akmp_t);
+
+ if (bss->param.bss_config.wpa_cfg.
+ pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *) tlv;
+ tlv_pwk_cipher->header.type = wlan_cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ tlv_pwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u16) + sizeof(t_u8) + sizeof(t_u8));
+ tlv_pwk_cipher->protocol = wlan_cpu_to_le16(PROTOCOL_WPA);
+ tlv_pwk_cipher->pairwise_cipher =
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa;
+ cmd_size += sizeof(MrvlIEtypes_pwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_pwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.
+ pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *) tlv;
+ tlv_pwk_cipher->header.type = wlan_cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ tlv_pwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u16) + sizeof(t_u8) + sizeof(t_u8));
+ tlv_pwk_cipher->protocol = wlan_cpu_to_le16(PROTOCOL_WPA2);
+ tlv_pwk_cipher->pairwise_cipher =
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa2;
+ cmd_size += sizeof(MrvlIEtypes_pwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_pwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
+ tlv_gwk_cipher = (MrvlIEtypes_gwk_cipher_t *) tlv;
+ tlv_gwk_cipher->header.type = wlan_cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+ tlv_gwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_gwk_cipher->group_cipher =
+ bss->param.bss_config.wpa_cfg.group_cipher;
+ cmd_size += sizeof(MrvlIEtypes_gwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_gwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.rsn_protection <= MTRUE) {
+ tlv_rsn_prot = (MrvlIEtypes_rsn_replay_prot_t *) tlv;
+ tlv_rsn_prot->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RSN_REPLAY_PROTECT);
+ tlv_rsn_prot->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_rsn_prot->rsn_replay_prot =
+ bss->param.bss_config.wpa_cfg.rsn_protection;
+ cmd_size += sizeof(MrvlIEtypes_rsn_replay_prot_t);
+ tlv += sizeof(MrvlIEtypes_rsn_replay_prot_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.length) {
+ tlv_passphrase = (MrvlIEtypes_passphrase_t *) tlv;
+ tlv_passphrase->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+ tlv_passphrase->header.len =
+ (t_u16) wlan_cpu_to_le16(bss->param.bss_config.wpa_cfg.length);
+ memcpy(pmpriv->adapter, tlv_passphrase->passphrase,
+ bss->param.bss_config.wpa_cfg.passphrase,
+ bss->param.bss_config.wpa_cfg.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.wpa_cfg.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.wpa_cfg.length;
+ }
+
+ if (bss->param.bss_config.wpa_cfg.gk_rekey_time < MAX_GRP_TIMER) {
+ tlv_rekey_time = (MrvlIEtypes_group_rekey_time_t *) tlv;
+ tlv_rekey_time->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_GRP_REKEY_TIME);
+ tlv_rekey_time->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_rekey_time->gk_rekey_time =
+ wlan_cpu_to_le32(bss->param.bss_config.wpa_cfg.gk_rekey_time);
+ cmd_size += sizeof(MrvlIEtypes_group_rekey_time_t);
+ tlv += sizeof(MrvlIEtypes_group_rekey_time_t);
+ }
+ } else {
+ if ((bss->param.bss_config.wep_cfg.key0.length) &&
+ ((bss->param.bss_config.wep_cfg.key0.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key0.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key0.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key0.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key0.key,
+ bss->param.bss_config.wep_cfg.key0.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key0.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key0.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key1.length) &&
+ ((bss->param.bss_config.wep_cfg.key1.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key1.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key1.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key1.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key1.key,
+ bss->param.bss_config.wep_cfg.key1.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key1.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key1.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key2.length) &&
+ ((bss->param.bss_config.wep_cfg.key2.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key2.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key2.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key2.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key2.key,
+ bss->param.bss_config.wep_cfg.key2.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key2.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key2.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key3.length) &&
+ ((bss->param.bss_config.wep_cfg.key3.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key3.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key3.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key3.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key3.key,
+ bss->param.bss_config.wep_cfg.key3.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key3.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key3.length;
+ }
+ }
+ if ((bss->param.bss_config.ht_cap_info)
+ ) {
+ tlv_htcap = (MrvlIETypes_HTCap_t *) tlv;
+ tlv_htcap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ tlv_htcap->header.len = wlan_cpu_to_le16(sizeof(HTCap_t));
+ tlv_htcap->ht_cap.ht_cap_info =
+ wlan_cpu_to_le16(bss->param.bss_config.ht_cap_info);
+ tlv_htcap->ht_cap.ampdu_param = bss->param.bss_config.ampdu_param;
+ memcpy(pmpriv->adapter, tlv_htcap->ht_cap.supported_mcs_set,
+ bss->param.bss_config.supported_mcs_set, 16);
+ tlv_htcap->ht_cap.ht_ext_cap =
+ wlan_cpu_to_le16(bss->param.bss_config.ht_ext_cap);
+ tlv_htcap->ht_cap.tx_bf_cap =
+ wlan_cpu_to_le32(bss->param.bss_config.tx_bf_cap);
+ tlv_htcap->ht_cap.asel = bss->param.bss_config.asel;
+ cmd_size += sizeof(MrvlIETypes_HTCap_t);
+ tlv += sizeof(MrvlIETypes_HTCap_t);
+ }
+ if (bss->param.bss_config.mgmt_ie_passthru_mask < (MAX_VALID_DWORD)) {
+ tlv_mgmt_ie_passthru = (MrvlIEtypes_mgmt_ie_passthru_t *) tlv;
+ tlv_mgmt_ie_passthru->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK);
+ tlv_mgmt_ie_passthru->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ /* keep copy in private data */
+ pmpriv->mgmt_frame_passthru_mask =
+ bss->param.bss_config.mgmt_ie_passthru_mask;
+ tlv_mgmt_ie_passthru->mgmt_ie_mask =
+ wlan_cpu_to_le32(bss->param.bss_config.mgmt_ie_passthru_mask);
+ cmd_size += sizeof(MrvlIEtypes_mgmt_ie_passthru_t);
+ tlv += sizeof(MrvlIEtypes_mgmt_ie_passthru_t);
+ }
+ if (((bss->param.bss_config.enable_2040coex == 0) ||
+ (bss->param.bss_config.enable_2040coex == 1))
+ ) {
+ tlv_2040_coex_enable = (MrvlIEtypes_2040_coex_enable_t *) tlv;
+ tlv_2040_coex_enable->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_2040_BSS_COEX_CONTROL);
+ tlv_2040_coex_enable->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_2040_coex_enable->enable_2040coex =
+ bss->param.bss_config.enable_2040coex;
+ cmd_size += sizeof(MrvlIEtypes_2040_coex_enable_t);
+ tlv += sizeof(MrvlIEtypes_2040_coex_enable_t);
+ }
+ if (bss->param.bss_config.wmm_para.qos_info == 0x80 ||
+ bss->param.bss_config.wmm_para.qos_info == 0x00) {
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *) tlv;
+ tlv_wmm_parameter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_VENDOR_SPECIFIC_IE);
+ tlv_wmm_parameter->header.len =
+ wlan_cpu_to_le16(sizeof(bss->param.bss_config.wmm_para));
+ memcpy(pmpriv->adapter, tlv_wmm_parameter->wmm_para.ouitype,
+ bss->param.bss_config.wmm_para.ouitype,
+ sizeof(tlv_wmm_parameter->wmm_para.ouitype));
+ tlv_wmm_parameter->wmm_para.ouisubtype =
+ bss->param.bss_config.wmm_para.ouisubtype;
+ tlv_wmm_parameter->wmm_para.version =
+ bss->param.bss_config.wmm_para.version;
+ tlv_wmm_parameter->wmm_para.qos_info =
+ bss->param.bss_config.wmm_para.qos_info;
+ for (ac = 0; ac < 4; ac++) {
+ tlv_wmm_parameter->wmm_para.ac_params[ac].aci_aifsn.aifsn =
+ bss->param.bss_config.wmm_para.ac_params[ac].aci_aifsn.aifsn;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_max =
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_max;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_min =
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_min;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].tx_op_limit =
+ wlan_cpu_to_le16(bss->param.bss_config.wmm_para.ac_params[ac].
+ tx_op_limit);
+ }
+ cmd_size += sizeof(MrvlIEtypes_wmm_parameter_t);
+ tlv += sizeof(MrvlIEtypes_wmm_parameter_t);
+ }
+
+ cmd->size = (t_u16) wlan_cpu_to_le16(cmd_size);
+ PRINTM(MCMND, "AP config: cmd_size=%d\n", cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sys_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_uap_cmd_sys_configure(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN pmlan_ioctl_req pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & cmd->params.sys_config;
+ MrvlIEtypes_MacAddr_t *mac_tlv = MNULL;
+ MrvlIEtypes_channel_band_t *chan_band_tlv = MNULL, *pdat_tlv_cb = MNULL;
+ MrvlIEtypes_beacon_period_t *bcn_pd_tlv = MNULL, *pdat_tlv_bcnpd = MNULL;
+ MrvlIEtypes_dtim_period_t *dtim_pd_tlv = MNULL, *pdat_tlv_dtimpd = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ MrvlIEtypesHeader_t *ie_header =
+ (MrvlIEtypesHeader_t *) sys_config->tlv_buffer;
+ t_u8 *ie = (t_u8 *) sys_config->tlv_buffer + sizeof(MrvlIEtypesHeader_t);
+ t_u16 req_len = 0, travel_len = 0;
+ custom_ie *cptr = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
+ sys_config->action = wlan_cpu_to_le16(cmd_action);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN);
+ if (pioctl_buf == MNULL) {
+ if (pdata_buf) {
+ switch (*(t_u16 *) pdata_buf) {
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ pdat_tlv_cb = (MrvlIEtypes_channel_band_t *) pdata_buf;
+ chan_band_tlv =
+ (MrvlIEtypes_channel_band_t *) sys_config->tlv_buffer;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(MrvlIEtypes_channel_band_t));
+ chan_band_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ chan_band_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_channel_band_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ chan_band_tlv->band_config = pdat_tlv_cb->band_config;
+ chan_band_tlv->channel = pdat_tlv_cb->channel;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ pdat_tlv_bcnpd = (MrvlIEtypes_beacon_period_t *) pdata_buf;
+ bcn_pd_tlv =
+ (MrvlIEtypes_beacon_period_t *) sys_config->tlv_buffer;
+ cmd->size =
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_beacon_period_t);
+ bcn_pd_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
+ bcn_pd_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_beacon_period_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ bcn_pd_tlv->beacon_period =
+ wlan_cpu_to_le16(pdat_tlv_bcnpd->beacon_period);
+ }
+ /* Add TLV_UAP_DTIM_PERIOD if it follws in pdata_buf */
+ pdat_tlv_dtimpd =
+ (MrvlIEtypes_dtim_period_t *) (((t_u8 *) pdata_buf)
+ +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ if (TLV_TYPE_UAP_DTIM_PERIOD == pdat_tlv_dtimpd->header.type) {
+ dtim_pd_tlv =
+ (MrvlIEtypes_dtim_period_t *) (sys_config->tlv_buffer +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ cmd->size += sizeof(MrvlIEtypes_dtim_period_t);
+ dtim_pd_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+ dtim_pd_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_dtim_period_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ dtim_pd_tlv->dtim_period = pdat_tlv_dtimpd->dtim_period;
+ }
+ }
+ /* Finalize cmd size */
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case TLV_TYPE_MGMT_IE:
+ cust_ie = (mlan_ds_misc_custom_ie *) pdata_buf;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN + sizeof(MrvlIEtypesHeader_t) +
+ cust_ie->len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header->len = wlan_cpu_to_le16(cust_ie->len);
+
+ if (ie && cust_ie->ie_data_list) {
+ req_len = cust_ie->len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+ while (req_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) & cust_ie->ie_data_list) +
+ travel_len);
+ travel_len +=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ memcpy(pmpriv->adapter, ie, cust_ie->ie_data_list,
+ cust_ie->len);
+ }
+ break;
+ default:
+ PRINTM(MERROR,
+ "Wrong data, or missing TLV_TYPE 0x%04x handler.\n",
+ *(t_u16 *) pdata_buf);
+ break;
+ }
+ goto done;
+ } else {
+ mac_tlv = (MrvlIEtypes_MacAddr_t *) sys_config->tlv_buffer;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_MacAddr_t));
+ mac_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ }
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR) {
+ mac_tlv = (MrvlIEtypes_MacAddr_t *) sys_config->tlv_buffer;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_MacAddr_t));
+ mac_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy(pmpriv->adapter, mac_tlv->mac, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ } else if ((bss->sub_command == MLAN_OID_UAP_BSS_CONFIG) &&
+ (cmd_action == HostCmd_ACT_GEN_SET)) {
+ ret = wlan_uap_cmd_ap_config(pmpriv, cmd, cmd_action, pioctl_buf);
+ goto done;
+ }
+ } else if (pioctl_buf->req_id == MLAN_IOCTL_MISC_CFG) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ if ((misc->sub_command == MLAN_OID_MISC_GEN_IE) &&
+ (misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE)
+ ) {
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypesHeader_t) +
+ misc->param.gen_ie.len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header->len = wlan_cpu_to_le16(misc->param.gen_ie.len);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy(pmpriv->adapter, ie, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ }
+ if ((misc->sub_command == MLAN_OID_MISC_CUSTOM_IE) &&
+ (misc->param.cust_ie.type == TLV_TYPE_MGMT_IE)) {
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypesHeader_t) +
+ misc->param.cust_ie.len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header->len = wlan_cpu_to_le16(misc->param.cust_ie.len);
+
+ if (ie && misc->param.cust_ie.ie_data_list) {
+ req_len = misc->param.cust_ie.len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ misc->param.cust_ie.ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(misc->param.cust_ie.ie_data_list[0].
+ ie_index);
+ while (req_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie
+ *) (((t_u8 *) & misc->param.cust_ie.ie_data_list) +
+ travel_len);
+ travel_len +=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ if (misc->param.cust_ie.len)
+ memcpy(pmpriv->adapter, ie,
+ misc->param.cust_ie.ie_data_list,
+ misc->param.cust_ie.len);
+ }
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles command resp for get uap settings
+ *
+ * @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
+ */
+static mlan_status
+wlan_uap_ret_cmd_ap_config(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & resp->params.sys_config;
+ mlan_ds_bss *bss = MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ MrvlIEtypes_MacAddr_t *tlv_mac = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_beacon_period = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtim_period = MNULL;
+ MrvlIEtypes_RatesParamSet_t *tlv_rates = MNULL;
+ MrvlIEtypes_tx_rate_t *tlv_txrate = MNULL;
+ MrvlIEtypes_mcbc_rate_t *tlv_mcbc_rate = MNULL;
+ MrvlIEtypes_tx_power_t *tlv_tx_power = MNULL;
+ MrvlIEtypes_bcast_ssid_t *tlv_bcast_ssid = MNULL;
+ MrvlIEtypes_antenna_mode_t *tlv_antenna = MNULL;
+ MrvlIEtypes_pkt_forward_t *tlv_pkt_forward = MNULL;
+ MrvlIEtypes_max_sta_count_t *tlv_sta_count = MNULL;
+ MrvlIEtypes_sta_ageout_t *tlv_sta_ageout = MNULL;
+ MrvlIEtypes_ps_sta_ageout_t *tlv_ps_sta_ageout = MNULL;
+ MrvlIEtypes_rts_threshold_t *tlv_rts_threshold = MNULL;
+ MrvlIEtypes_frag_threshold_t *tlv_frag_threshold = MNULL;
+ MrvlIEtypes_retry_limit_t *tlv_retry_limit = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_timeout_t *tlv_pairwise_timeout = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_retries_t *tlv_pairwise_retries = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_timeout_t *tlv_groupwise_timeout = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_retries_t *tlv_groupwise_retries = MNULL;
+ MrvlIEtypes_mgmt_ie_passthru_t *tlv_mgmt_ie_passthru = MNULL;
+ MrvlIEtypes_2040_coex_enable_t *tlv_2040_coex_enable = MNULL;
+ MrvlIEtypes_mac_filter_t *tlv_mac_filter = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_chan_band = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_auth_type_t *tlv_auth_type = MNULL;
+ MrvlIEtypes_encrypt_protocol_t *tlv_encrypt_protocol = MNULL;
+ MrvlIEtypes_akmp_t *tlv_akmp = MNULL;
+ MrvlIEtypes_pwk_cipher_t *tlv_pwk_cipher = MNULL;
+ MrvlIEtypes_gwk_cipher_t *tlv_gwk_cipher = MNULL;
+ MrvlIEtypes_rsn_replay_prot_t *tlv_rsn_prot = MNULL;
+ MrvlIEtypes_passphrase_t *tlv_passphrase = MNULL;
+#ifdef WIFI_DIRECT_SUPPORT
+ MrvlIEtypes_psk_t *tlv_psk = MNULL;
+#endif /* WIFI_DIRECT_SUPPORT */
+ MrvlIEtypes_group_rekey_time_t *tlv_rekey_time = MNULL;
+ MrvlIEtypes_wep_key_t *tlv_wep_key = MNULL;
+ MrvlIEtypes_preamble_t *tlv_preamble = MNULL;
+ MrvlIEtypes_bss_status_t *tlv_bss_status = MNULL;
+ MrvlIETypes_HTCap_t *tlv_htcap = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+
+ wep_key *pkey = MNULL;
+ t_u16 i;
+ t_u16 ac;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ tlv = (MrvlIEtypesHeader_t *) sys_config->tlv_buffer;
+ tlv_buf_left = resp->size - (sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+
+ if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Error processing uAP sys config TLVs, bytes left < TLV length\n");
+ break;
+ }
+
+ switch (tlv_type) {
+ case TLV_TYPE_UAP_MAC_ADDRESS:
+ tlv_mac = (MrvlIEtypes_MacAddr_t *) tlv;
+ memcpy(pmpriv->adapter, &bss->param.bss_config.mac_addr,
+ tlv_mac->mac, MLAN_MAC_ADDR_LENGTH);
+ break;
+ case TLV_TYPE_SSID:
+ tlv_ssid = (MrvlIEtypes_SsIdParamSet_t *) tlv;
+ bss->param.bss_config.ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, tlv_len);
+ memcpy(pmpriv->adapter, bss->param.bss_config.ssid.ssid,
+ tlv_ssid->ssid, MIN(MLAN_MAX_SSID_LENGTH, tlv_len));
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ tlv_beacon_period = (MrvlIEtypes_beacon_period_t *) tlv;
+ bss->param.bss_config.beacon_period =
+ wlan_le16_to_cpu(tlv_beacon_period->beacon_period);
+ pmpriv->uap_state_chan_cb.beacon_period =
+ wlan_le16_to_cpu(tlv_beacon_period->beacon_period);
+ break;
+ case TLV_TYPE_UAP_DTIM_PERIOD:
+ tlv_dtim_period = (MrvlIEtypes_dtim_period_t *) tlv;
+ bss->param.bss_config.dtim_period = tlv_dtim_period->dtim_period;
+ pmpriv->uap_state_chan_cb.dtim_period =
+ tlv_dtim_period->dtim_period;
+ break;
+ case TLV_TYPE_RATES:
+ tlv_rates = (MrvlIEtypes_RatesParamSet_t *) tlv;
+ memcpy(pmpriv->adapter, bss->param.bss_config.rates,
+ tlv_rates->rates, MIN(MAX_DATA_RATES, tlv_len));
+ break;
+ case TLV_TYPE_UAP_TX_DATA_RATE:
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *) tlv;
+ bss->param.bss_config.tx_data_rate =
+ wlan_le16_to_cpu(tlv_txrate->tx_data_rate);
+ break;
+ case TLV_TYPE_UAP_MCBC_DATA_RATE:
+ tlv_mcbc_rate = (MrvlIEtypes_mcbc_rate_t *) tlv;
+ bss->param.bss_config.mcbc_data_rate =
+ wlan_le16_to_cpu(tlv_mcbc_rate->mcbc_data_rate);
+ break;
+ case TLV_TYPE_UAP_TX_POWER:
+ tlv_tx_power = (MrvlIEtypes_tx_power_t *) tlv;
+ bss->param.bss_config.tx_power_level = tlv_tx_power->tx_power;
+ break;
+ case TLV_TYPE_UAP_BCAST_SSID_CTL:
+ tlv_bcast_ssid = (MrvlIEtypes_bcast_ssid_t *) tlv;
+ bss->param.bss_config.bcast_ssid_ctl =
+ tlv_bcast_ssid->bcast_ssid_ctl;
+ break;
+ case TLV_TYPE_UAP_ANTENNA_CTL:
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *) tlv;
+ if (tlv_antenna->which_antenna == TX_ANTENNA)
+ bss->param.bss_config.tx_antenna = tlv_antenna->antenna_mode;
+ else if (tlv_antenna->which_antenna == RX_ANTENNA)
+ bss->param.bss_config.rx_antenna = tlv_antenna->antenna_mode;
+ break;
+ case TLV_TYPE_UAP_PKT_FWD_CTL:
+ tlv_pkt_forward = (MrvlIEtypes_pkt_forward_t *) tlv;
+ bss->param.bss_config.pkt_forward_ctl =
+ tlv_pkt_forward->pkt_forward_ctl;
+ break;
+ case TLV_TYPE_UAP_MAX_STA_CNT:
+ tlv_sta_count = (MrvlIEtypes_max_sta_count_t *) tlv;
+ bss->param.bss_config.max_sta_count =
+ wlan_le16_to_cpu(tlv_sta_count->max_sta_count);
+ break;
+ case TLV_TYPE_UAP_STA_AGEOUT_TIMER:
+ tlv_sta_ageout = (MrvlIEtypes_sta_ageout_t *) tlv;
+ bss->param.bss_config.sta_ageout_timer =
+ wlan_le32_to_cpu(tlv_sta_ageout->sta_ageout_timer);
+ break;
+ case TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER:
+ tlv_ps_sta_ageout = (MrvlIEtypes_ps_sta_ageout_t *) tlv;
+ bss->param.bss_config.ps_sta_ageout_timer =
+ wlan_le32_to_cpu(tlv_ps_sta_ageout->ps_sta_ageout_timer);
+ break;
+ case TLV_TYPE_UAP_RTS_THRESHOLD:
+ tlv_rts_threshold = (MrvlIEtypes_rts_threshold_t *) tlv;
+ bss->param.bss_config.rts_threshold =
+ wlan_le16_to_cpu(tlv_rts_threshold->rts_threshold);
+ break;
+ case TLV_TYPE_UAP_FRAG_THRESHOLD:
+ tlv_frag_threshold = (MrvlIEtypes_frag_threshold_t *) tlv;
+ bss->param.bss_config.frag_threshold =
+ wlan_le16_to_cpu(tlv_frag_threshold->frag_threshold);
+ break;
+ case TLV_TYPE_UAP_RETRY_LIMIT:
+ tlv_retry_limit = (MrvlIEtypes_retry_limit_t *) tlv;
+ bss->param.bss_config.retry_limit = tlv_retry_limit->retry_limit;
+ break;
+ case TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT:
+ tlv_pairwise_timeout = (MrvlIEtypes_eapol_pwk_hsk_timeout_t *) tlv;
+ bss->param.bss_config.pairwise_update_timeout =
+ wlan_le32_to_cpu(tlv_pairwise_timeout->pairwise_update_timeout);
+ break;
+ case TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES:
+ tlv_pairwise_retries = (MrvlIEtypes_eapol_pwk_hsk_retries_t *) tlv;
+ bss->param.bss_config.pwk_retries =
+ wlan_le32_to_cpu(tlv_pairwise_retries->pwk_retries);
+ break;
+ case TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT:
+ tlv_groupwise_timeout = (MrvlIEtypes_eapol_gwk_hsk_timeout_t *) tlv;
+ bss->param.bss_config.groupwise_update_timeout =
+ wlan_le32_to_cpu(tlv_groupwise_timeout->
+ groupwise_update_timeout);
+ break;
+ case TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES:
+ tlv_groupwise_retries = (MrvlIEtypes_eapol_gwk_hsk_retries_t *) tlv;
+ bss->param.bss_config.gwk_retries =
+ wlan_le32_to_cpu(tlv_groupwise_retries->gwk_retries);
+ break;
+ case TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK:
+ tlv_mgmt_ie_passthru = (MrvlIEtypes_mgmt_ie_passthru_t *) tlv;
+ bss->param.bss_config.mgmt_ie_passthru_mask =
+ wlan_le32_to_cpu(tlv_mgmt_ie_passthru->mgmt_ie_mask);
+ break;
+ case TLV_TYPE_2040_BSS_COEX_CONTROL:
+ tlv_2040_coex_enable = (MrvlIEtypes_2040_coex_enable_t *) tlv;
+ bss->param.bss_config.enable_2040coex =
+ tlv_2040_coex_enable->enable_2040coex;
+ break;
+ case TLV_TYPE_UAP_STA_MAC_ADDR_FILTER:
+ tlv_mac_filter = (MrvlIEtypes_mac_filter_t *) tlv;
+ bss->param.bss_config.filter.mac_count =
+ MIN(MAX_MAC_FILTER_NUM, tlv_mac_filter->count);
+ bss->param.bss_config.filter.filter_mode =
+ tlv_mac_filter->filter_mode;
+ memcpy(pmpriv->adapter,
+ (t_u8 *) bss->param.bss_config.filter.mac_list,
+ tlv_mac_filter->mac_address,
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count);
+ break;
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ tlv_chan_band = (MrvlIEtypes_channel_band_t *) tlv;
+ bss->param.bss_config.band_cfg = tlv_chan_band->band_config;
+ bss->param.bss_config.channel = tlv_chan_band->channel;
+ pmpriv->uap_state_chan_cb.band_config = tlv_chan_band->band_config;
+ pmpriv->uap_state_chan_cb.channel = tlv_chan_band->channel;
+ break;
+ case TLV_TYPE_CHANLIST:
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ bss->param.bss_config.num_of_chan =
+ tlv_len / sizeof(ChanScanParamSet_t);
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0; i < bss->param.bss_config.num_of_chan; i++) {
+ bss->param.bss_config.chan_list[i].chan_number =
+ pscan_chan->chan_number;
+ bss->param.bss_config.chan_list[i].band_config_type =
+ pscan_chan->radio_type;
+ pscan_chan++;
+ }
+ break;
+ case TLV_TYPE_AUTH_TYPE:
+ tlv_auth_type = (MrvlIEtypes_auth_type_t *) tlv;
+ bss->param.bss_config.auth_mode = tlv_auth_type->auth_type;
+ break;
+ case TLV_TYPE_UAP_ENCRYPT_PROTOCOL:
+ tlv_encrypt_protocol = (MrvlIEtypes_encrypt_protocol_t *) tlv;
+ bss->param.bss_config.protocol =
+ wlan_le16_to_cpu(tlv_encrypt_protocol->protocol);
+ break;
+ case TLV_TYPE_UAP_AKMP:
+ tlv_akmp = (MrvlIEtypes_akmp_t *) tlv;
+ bss->param.bss_config.key_mgmt =
+ wlan_le16_to_cpu(tlv_akmp->key_mgmt);
+ if (tlv_len > sizeof(t_u16))
+ bss->param.bss_config.key_mgmt_operation =
+ wlan_le16_to_cpu(tlv_akmp->key_mgmt_operation);
+ break;
+ case TLV_TYPE_PWK_CIPHER:
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *) tlv;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) & PROTOCOL_WPA)
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa =
+ tlv_pwk_cipher->pairwise_cipher;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) & PROTOCOL_WPA2)
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa2 =
+ tlv_pwk_cipher->pairwise_cipher;
+ break;
+ case TLV_TYPE_GWK_CIPHER:
+ tlv_gwk_cipher = (MrvlIEtypes_gwk_cipher_t *) tlv;
+ bss->param.bss_config.wpa_cfg.group_cipher =
+ tlv_gwk_cipher->group_cipher;
+ break;
+ case TLV_TYPE_UAP_RSN_REPLAY_PROTECT:
+ tlv_rsn_prot = (MrvlIEtypes_rsn_replay_prot_t *) tlv;
+ bss->param.bss_config.wpa_cfg.rsn_protection =
+ tlv_rsn_prot->rsn_replay_prot;
+ break;
+ case TLV_TYPE_UAP_WPA_PASSPHRASE:
+ tlv_passphrase = (MrvlIEtypes_passphrase_t *) tlv;
+ bss->param.bss_config.wpa_cfg.length =
+ MIN(MLAN_PMK_HEXSTR_LENGTH, tlv_len);
+ memcpy(pmpriv->adapter, bss->param.bss_config.wpa_cfg.passphrase,
+ tlv_passphrase->passphrase,
+ bss->param.bss_config.wpa_cfg.length);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case TLV_TYPE_UAP_PSK:
+ tlv_psk = (MrvlIEtypes_psk_t *) tlv;
+ memcpy(pmpriv->adapter, bss->param.bss_config.psk, tlv_psk->psk,
+ MIN(MLAN_MAX_KEY_LENGTH, tlv_len));
+ break;
+#endif /* WIFI_DIRECT_SUPPORT */
+ case TLV_TYPE_UAP_GRP_REKEY_TIME:
+ tlv_rekey_time = (MrvlIEtypes_group_rekey_time_t *) tlv;
+ bss->param.bss_config.wpa_cfg.gk_rekey_time =
+ wlan_le32_to_cpu(tlv_rekey_time->gk_rekey_time);
+ break;
+ case TLV_TYPE_UAP_WEP_KEY:
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ pkey = MNULL;
+ if (tlv_wep_key->key_index == 0)
+ pkey = &bss->param.bss_config.wep_cfg.key0;
+ else if (tlv_wep_key->key_index == 1)
+ pkey = &bss->param.bss_config.wep_cfg.key1;
+ else if (tlv_wep_key->key_index == 2)
+ pkey = &bss->param.bss_config.wep_cfg.key2;
+ else if (tlv_wep_key->key_index == 3)
+ pkey = &bss->param.bss_config.wep_cfg.key3;
+ if (pkey) {
+ pkey->key_index = tlv_wep_key->key_index;
+ pkey->is_default = tlv_wep_key->is_default;
+ pkey->length = MIN(MAX_WEP_KEY_SIZE, (tlv_len - 2));
+ memcpy(pmpriv->adapter, pkey->key, tlv_wep_key->key,
+ pkey->length);
+ }
+ break;
+ case TLV_TYPE_UAP_PREAMBLE_CTL:
+ tlv_preamble = (MrvlIEtypes_preamble_t *) tlv;
+ bss->param.bss_config.preamble_type = tlv_preamble->preamble_type;
+ break;
+ case TLV_TYPE_BSS_STATUS:
+ tlv_bss_status = (MrvlIEtypes_bss_status_t *) tlv;
+ bss->param.bss_config.bss_status =
+ wlan_le16_to_cpu(tlv_bss_status->bss_status);
+ pmpriv->uap_bss_started =
+ (bss->param.bss_config.bss_status) ? MTRUE : MFALSE;
+ break;
+ case HT_CAPABILITY:
+ tlv_htcap = (MrvlIETypes_HTCap_t *) tlv;
+ bss->param.bss_config.ht_cap_info =
+ wlan_le16_to_cpu(tlv_htcap->ht_cap.ht_cap_info);
+ bss->param.bss_config.ampdu_param = tlv_htcap->ht_cap.ampdu_param;
+ memcpy(pmpriv->adapter, bss->param.bss_config.supported_mcs_set,
+ tlv_htcap->ht_cap.supported_mcs_set, 16);
+ bss->param.bss_config.ht_ext_cap =
+ wlan_le16_to_cpu(tlv_htcap->ht_cap.ht_ext_cap);
+ bss->param.bss_config.tx_bf_cap =
+ wlan_le32_to_cpu(tlv_htcap->ht_cap.tx_bf_cap);
+ bss->param.bss_config.asel = tlv_htcap->ht_cap.asel;
+ break;
+ case TLV_TYPE_VENDOR_SPECIFIC_IE:
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *) tlv;
+ bss->param.bss_config.wmm_para.qos_info =
+ tlv_wmm_parameter->wmm_para.qos_info;
+ for (ac = 0; ac < 4; ac++) {
+ bss->param.bss_config.wmm_para.ac_params[ac].aci_aifsn.aifsn =
+ tlv_wmm_parameter->wmm_para.ac_params[ac].aci_aifsn.aifsn;
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_max =
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_max;
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_min =
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_min;
+ bss->param.bss_config.wmm_para.ac_params[ac].tx_op_limit =
+ wlan_le16_to_cpu(tlv_wmm_parameter->wmm_para.ac_params[ac].
+ tx_op_limit);
+ }
+ break;
+ }
+
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sys_reset
+ * Clear various private state variables used by DFS.
+ *
+ * @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
+ */
+static mlan_status
+wlan_uap_ret_sys_reset(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+
+ pmpriv->uap_state_chan_cb.band_config = 0;
+ pmpriv->uap_state_chan_cb.channel = 0;
+ pmpriv->uap_state_chan_cb.beacon_period = 0;
+ pmpriv->uap_state_chan_cb.dtim_period = 0;
+
+ /* assume default 11d/11h states are off, should check with FW */
+ /* currently don't clear domain_info... global, could be from STA */
+ wlan_11d_priv_init(pmpriv);
+ wlan_11h_priv_init(pmpriv);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sys_config
+ *
+ * @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
+ */
+static mlan_status
+wlan_uap_ret_sys_config(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ int resp_len = 0, travel_len = 0;
+ int i = 0;
+ custom_ie *cptr;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & resp->params.sys_config;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ MrvlIEtypes_MacAddr_t *tlv =
+ (MrvlIEtypes_MacAddr_t *) sys_config->tlv_buffer;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ tlvbuf_max_mgmt_ie *max_mgmt_ie = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_cb = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_bcnpd = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtimpd = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR) {
+ if (TLV_TYPE_UAP_MAC_ADDRESS ==
+ wlan_le16_to_cpu(tlv->header.type)) {
+ memcpy(pmpriv->adapter, &bss->param.mac_addr, tlv->mac,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+ } else if ((bss->sub_command == MLAN_OID_UAP_BSS_CONFIG) &&
+ (pioctl_buf->action == MLAN_ACT_GET)) {
+ wlan_uap_ret_cmd_ap_config(pmpriv, resp, pioctl_buf);
+ }
+ }
+ if (pioctl_buf->req_id == MLAN_IOCTL_MISC_CFG) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ cust_ie = (mlan_ds_misc_custom_ie *) sys_config->tlv_buffer;
+ max_mgmt_ie =
+ (tlvbuf_max_mgmt_ie *) (sys_config->tlv_buffer + cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t));
+ if ((pioctl_buf->action == MLAN_ACT_GET) &&
+ (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)) {
+
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len = wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) cust_ie->ie_data_list) +
+ travel_len);
+ cptr->ie_index = wlan_le16_to_cpu(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_le16_to_cpu(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(cptr->ie_length);
+ travel_len +=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ resp_len -=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ }
+ memcpy(pmpriv->adapter, &misc->param.cust_ie, cust_ie,
+ MIN(sizeof(mlan_ds_misc_custom_ie) -
+ sizeof(tlvbuf_max_mgmt_ie),
+ (cust_ie->len + sizeof(MrvlIEtypesHeader_t))));
+ if (max_mgmt_ie) {
+ max_mgmt_ie->type = wlan_le16_to_cpu(max_mgmt_ie->type);
+ if (max_mgmt_ie->type == TLV_TYPE_MAX_MGMT_IE) {
+ max_mgmt_ie->len = wlan_le16_to_cpu(max_mgmt_ie->len);
+ max_mgmt_ie->count =
+ wlan_le16_to_cpu(max_mgmt_ie->count);
+ for (i = 0; i < max_mgmt_ie->count; i++) {
+ max_mgmt_ie->info[i].buf_size =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].buf_size);
+ max_mgmt_ie->info[i].buf_count =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].
+ buf_count);
+ }
+ /* Append max_mgmt_ie TLV after custom_ie */
+ memcpy(pmpriv->adapter,
+ (t_u8 *) & misc->param.cust_ie + (cust_ie->len +
+ sizeof
+ (MrvlIEtypesHeader_t)),
+ max_mgmt_ie, MIN(sizeof(tlvbuf_max_mgmt_ie),
+ max_mgmt_ie->len +
+ sizeof(MrvlIEtypesHeader_t)));
+ }
+ }
+ }
+ }
+ } else { /* no ioctl: driver generated get/set */
+ switch (wlan_le16_to_cpu(tlv->header.type)) {
+ case TLV_TYPE_UAP_MAC_ADDRESS:
+ memcpy(pmpriv->adapter, pmpriv->curr_addr, tlv->mac,
+ MLAN_MAC_ADDR_LENGTH);
+ break;
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ tlv_cb = (MrvlIEtypes_channel_band_t *) tlv;
+ pmpriv->uap_state_chan_cb.band_config = tlv_cb->band_config;
+ pmpriv->uap_state_chan_cb.channel = tlv_cb->channel;
+ /* call callback waiting for channel info */
+ if (pmpriv->uap_state_chan_cb.get_chan_callback)
+ pmpriv->uap_state_chan_cb.get_chan_callback(pmpriv);
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ tlv_bcnpd = (MrvlIEtypes_beacon_period_t *) tlv;
+ pmpriv->uap_state_chan_cb.beacon_period =
+ wlan_le16_to_cpu(tlv_bcnpd->beacon_period);
+ /* copy dtim_period as well if it follows */
+ tlv_dtimpd =
+ (MrvlIEtypes_dtim_period_t *) (((t_u8 *) tlv) +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ if (TLV_TYPE_UAP_DTIM_PERIOD ==
+ wlan_le16_to_cpu(tlv_dtimpd->header.type))
+ pmpriv->uap_state_chan_cb.dtim_period = tlv_dtimpd->dtim_period;
+ /* call callback waiting for beacon/dtim info */
+ if (pmpriv->uap_state_chan_cb.get_chan_callback)
+ pmpriv->uap_state_chan_cb.get_chan_callback(pmpriv);
+ break;
+ case TLV_TYPE_MGMT_IE:
+ if ((pmpriv->adapter->state_rdh.stage == RDH_SET_CUSTOM_IE) ||
+ (pmpriv->adapter->state_rdh.stage == RDH_REM_CUSTOM_IE))
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ break;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @param pdata_buf A pointer to information buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_uap_cmd_snmp_mib(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN pmlan_ioctl_req pioctl_buf, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *psnmp_oid = MNULL;
+ t_u32 ul_temp;
+ t_u8 i;
+
+ t_u8 snmp_oids[] = {
+ tkip_mic_failures,
+ ccmp_decrypt_errors,
+ wep_undecryptable_count,
+ wep_icv_error_count,
+ decrypt_failure_count,
+ dot11_mcast_tx_count,
+ dot11_failed_count,
+ dot11_retry_count,
+ dot11_multi_retry_count,
+ dot11_frame_dup_count,
+ dot11_rts_success_count,
+ dot11_rts_failure_count,
+ dot11_ack_failure_count,
+ dot11_rx_fragment_count,
+ dot11_mcast_rx_frame_count,
+ dot11_fcs_error_count,
+ dot11_tx_frame_count,
+ dot11_rsna_tkip_cm_invoked,
+ dot11_rsna_4way_hshk_failures,
+ };
+
+ ENTER();
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(t_u16) + S_DS_GEN +
+ sizeof(snmp_oids) *
+ sizeof(MrvlIEtypes_snmp_oid_t));
+ psnmp_oid = (t_u8 *) & psnmp_mib->oid;
+ for (i = 0; i < sizeof(snmp_oids); i++) {
+ /* SNMP OID header type */
+ *(t_u16 *) psnmp_oid = wlan_cpu_to_le16(snmp_oids[i]);
+ psnmp_oid += sizeof(t_u16);
+ /* SNMP OID header length */
+ *(t_u16 *) psnmp_oid = wlan_cpu_to_le16(sizeof(t_u32));
+ psnmp_oid += sizeof(t_u16) + sizeof(t_u32);
+ }
+ } else { /* cmd_action == ACT_SET */
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+
+ switch (cmd_oid) {
+ case Dot11D_i:
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) cmd_oid);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ break;
+ default:
+ PRINTM(MERROR, "Unsupported OID.\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @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
+ */
+static mlan_status
+wlan_uap_ret_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib =
+ (HostCmd_DS_802_11_SNMP_MIB *) & resp->params.smib;
+ mlan_ds_get_info *info;
+ t_u8 *psnmp_oid = MNULL;
+ t_u32 data;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+
+ ENTER();
+ if (psnmp_mib->query_type == HostCmd_ACT_GEN_GET) {
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ tlv_buf_left = resp->size - (sizeof(t_u16) + S_DS_GEN);
+ psnmp_oid = (t_u8 *) & psnmp_mib->oid;
+ while (tlv_buf_left >= sizeof(MrvlIEtypes_snmp_oid_t)) {
+ tlv_type = wlan_le16_to_cpu(*(t_u16 *) psnmp_oid);
+ psnmp_oid += sizeof(t_u16) + sizeof(t_u16);
+ memcpy(pmadapter, &data, psnmp_oid, sizeof(t_u32));
+ switch (tlv_type) {
+ case tkip_mic_failures:
+ info->param.ustats.tkip_mic_failures = wlan_le32_to_cpu(data);
+ break;
+ case ccmp_decrypt_errors:
+ info->param.ustats.ccmp_decrypt_errors = wlan_le32_to_cpu(data);
+ break;
+ case wep_undecryptable_count:
+ info->param.ustats.wep_undecryptable_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case wep_icv_error_count:
+ info->param.ustats.wep_icv_error_count = wlan_le32_to_cpu(data);
+ break;
+ case decrypt_failure_count:
+ info->param.ustats.decrypt_failure_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_mcast_tx_count:
+ info->param.ustats.mcast_tx_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_failed_count:
+ info->param.ustats.failed_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_retry_count:
+ info->param.ustats.retry_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_multi_retry_count:
+ info->param.ustats.multi_retry_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_frame_dup_count:
+ info->param.ustats.frame_dup_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rts_success_count:
+ info->param.ustats.rts_success_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rts_failure_count:
+ info->param.ustats.rts_failure_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_ack_failure_count:
+ info->param.ustats.ack_failure_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rx_fragment_count:
+ info->param.ustats.rx_fragment_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_mcast_rx_frame_count:
+ info->param.ustats.mcast_rx_frame_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_fcs_error_count:
+ info->param.ustats.fcs_error_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_tx_frame_count:
+ info->param.ustats.tx_frame_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rsna_tkip_cm_invoked:
+ info->param.ustats.rsna_tkip_cm_invoked =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rsna_4way_hshk_failures:
+ info->param.ustats.rsna_4way_hshk_failures =
+ wlan_le32_to_cpu(data);
+ break;
+ }
+ tlv_buf_left -= sizeof(MrvlIEtypes_snmp_oid_t);
+ psnmp_oid += sizeof(t_u32);
+ }
+ } else { /* ACT_SET */
+ switch (psnmp_mib->oid) {
+ case Dot11D_i:
+ data = wlan_le16_to_cpu(*((t_u16 *) (psnmp_mib->value)));
+ /* Set 11d state to private */
+ pmpriv->state_11d.enable_11d = data;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ pmpriv->state_11d.user_enable_11d = data;
+ break;
+ case Dot11H_i:
+ data = wlan_le16_to_cpu(*((t_u16 *) (psnmp_mib->value)));
+ /* Set 11h state to priv */
+ pmpriv->intf_state_11h.is_11h_active = (data & ENABLE_11H_MASK);
+ /* Set radar_det state to adapter */
+ pmpriv->adapter->state_11h.is_master_radar_det_active
+ = (data & MASTER_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ pmpriv->adapter->state_11h.is_slave_radar_det_active
+ = (data & SLAVE_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ break;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauth station
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_cmd_sta_deauth(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_STA_DEAUTH *pcmd_sta_deauth =
+ (HostCmd_DS_STA_DEAUTH *) & cmd->params.sta_deauth;
+ mlan_deauth_param *deauth = (mlan_deauth_param *) pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_STA_DEAUTH);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_STA_DEAUTH));
+ memcpy(pmpriv->adapter, pcmd_sta_deauth->mac, deauth->mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pcmd_sta_deauth->reason = wlan_cpu_to_le16(deauth->reason_code);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of key material
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_cmd_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u16 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material = &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *) pdata_buf;
+ MrvlIEtypes_MacAddr_t *tlv = MNULL;
+ const t_u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ t_u16 key_param_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size = wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN);
+ goto done;
+ }
+
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ if (pkey->is_wapi_key) {
+ PRINTM(MINFO, "Set WAPI Key\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_WAPI);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED));
+
+ pkey_material->key_param_set.key[0] = pkey->key_index;
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key[1] = 1;
+ else
+ pkey_material->key_param_set.key[1] = 0; /* set 0 when re-key */
+
+ if (0 != memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) { /* WAPI
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_UNICAST);
+ if ((sta_ptr = wlan_add_station_entry(pmpriv, pkey->mac_addr))) {
+ PRINTM(MCMND, "station: wapi_key_on\n");
+ sta_ptr->wapi_key_on = MTRUE;
+ }
+ } else { /* WAPI group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_MCAST);
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ }
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(WAPI_KEY_LEN);
+ memcpy(pmpriv->adapter, &pkey_material->key_param_set.key[2],
+ pkey->key_material, pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv =
+ (MrvlIEtypes_MacAddr_t *) ((t_u8 *) & pkey_material->key_param_set +
+ key_param_len);
+ tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_STA_MAC_ADDRESS);
+ tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmpriv->adapter, tlv->mac, pkey->mac_addr, MLAN_MAC_ADDR_LENGTH);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN + sizeof(MrvlIEtypes_MacAddr_t));
+ goto done;
+ }
+ if (pkey->key_len == WPA_AES_KEY_LEN) {
+ PRINTM(MCMND, "WPA_AES\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+ if (memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* AES
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+ else /* AES group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+ } else if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ PRINTM(MCMND, "WPA_TKIP\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+ if (memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* TKIP
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+ else /* TKIP group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+ }
+
+ if (pkey_material->key_param_set.key_type_id) {
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(pkey->key_len);
+ memcpy(pmpriv->adapter, pkey_material->key_param_set.key,
+ pkey->key_material, pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16((t_u16) pkey->key_len + KEYPARAMSET_FIXED_LEN);
+ key_param_len =
+ (pkey->key_len + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+
+ tlv =
+ (MrvlIEtypes_MacAddr_t *) ((t_u8 *) & pkey_material->key_param_set +
+ key_param_len);
+ tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_STA_MAC_ADDRESS);
+ tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmpriv->adapter, tlv->mac, pkey->mac_addr, MLAN_MAC_ADDR_LENGTH);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN + sizeof(MrvlIEtypes_MacAddr_t));
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of sta_list
+ *
+ * @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
+ */
+static mlan_status
+wlan_uap_ret_sta_list(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_STA_LIST *sta_list =
+ (HostCmd_DS_STA_LIST *) & resp->params.sta_list;
+ mlan_ds_get_info *info;
+ MrvlIEtypes_sta_info_t *tlv = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ info->param.sta_list.sta_count = wlan_le16_to_cpu(sta_list->sta_count);
+ tlv =
+ (MrvlIEtypes_sta_info_t *) ((t_u8 *) sta_list +
+ sizeof(HostCmd_DS_STA_LIST));
+ info->param.sta_list.sta_count =
+ MIN(info->param.sta_list.sta_count, MAX_NUM_CLIENTS);
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ memcpy(pmpriv->adapter, info->param.sta_list.info[i].mac_address,
+ tlv->mac_address, MLAN_MAC_ADDR_LENGTH);
+ info->param.sta_list.info[i].power_mfg_status =
+ tlv->power_mfg_status;
+ info->param.sta_list.info[i].rssi = tlv->rssi;
+ tlv++;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ * @param sta_ptr A pointer to sta_node
+ *
+ * @return N/A
+ */
+static void
+wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent,
+ sta_node * sta_ptr)
+{
+ t_u16 tlv_type, tlv_len;
+ t_u16 frame_control, frame_sub_type = 0;
+ t_u8 *assoc_req_ie = MNULL;
+ t_u8 ie_len = 0, assoc_ie_len = 0;
+ IEEEtypes_HTCap_t *pht_cap = MNULL;
+ int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv = (MrvlIEtypesHeader_t *)
+ (pevent->pbuf + pevent->data_offset + ASSOC_EVENT_FIX_SIZE);
+ MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
+
+ ENTER();
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_UAP_MGMT_FRAME) {
+ mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *) tlv;
+ memcpy(priv->adapter, &frame_control,
+ (t_u8 *) & (mgmt_tlv->frame_control), sizeof(frame_control));
+ frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(frame_control);
+ if ((mgmt_tlv->frame_control.type == 0) &&
+ ((frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
+ (frame_sub_type == SUBTYPE_REASSOC_REQUEST))) {
+
+ if (frame_sub_type == SUBTYPE_ASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_AssocRqst_t);
+ else if (frame_sub_type == SUBTYPE_REASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_ReAssocRqst_t);
+
+ ie_len = tlv_len - sizeof(IEEEtypes_FrameCtl_t) - assoc_ie_len;
+ assoc_req_ie =
+ (t_u8 *) tlv + sizeof(MrvlIETypes_MgmtFrameSet_t) +
+ assoc_ie_len;
+ pht_cap =
+ (IEEEtypes_HTCap_t *) wlan_get_specific_ie(priv,
+ assoc_req_ie,
+ ie_len,
+ HT_CAPABILITY);
+ if (pht_cap) {
+ PRINTM(MCMND, "STA supports 11n\n");
+ sta_ptr->is_11n_enabled = MTRUE;
+ if (GETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info))
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ } else {
+ PRINTM(MCMND, "STA doesn't support 11n\n");
+ }
+ break;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+
+ return;
+}
+
+/** Fixed size of bss start event */
+#define BSS_START_EVENT_FIX_SIZE 12
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void
+wlan_check_uap_capability(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - BSS_START_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *) (pevent->pbuf + pevent->data_offset +
+ BSS_START_EVENT_FIX_SIZE);
+ const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+ IEEEtypes_WmmParameter_t *pWmmParamIe = MNULL;
+ priv->wmm_enabled = MFALSE;
+ priv->pkt_fwd = MFALSE;
+ priv->is_11n_enabled = MFALSE;
+
+ ENTER();
+
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == HT_CAPABILITY) {
+ DBG_HEXDUMP(MCMD_D, "HT_CAP tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->is_11n_enabled = MTRUE;
+ }
+ if (tlv_type == VENDOR_SPECIFIC_221) {
+ if (!memcmp
+ (priv->adapter, (t_u8 *) tlv + sizeof(MrvlIEtypesHeader_t),
+ wmm_oui, sizeof(wmm_oui))) {
+ DBG_HEXDUMP(MCMD_D, "wmm ie tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->wmm_enabled = MFALSE;
+ wlan_wmm_setup_ac_downgrade(priv);
+ priv->wmm_enabled = MTRUE;
+ pWmmParamIe = (IEEEtypes_WmmParameter_t *) ((t_u8 *) tlv + 2);
+ pWmmParamIe->vend_hdr.len = (t_u8) tlv_len;
+ pWmmParamIe->vend_hdr.element_id = WMM_IE;
+ wlan_wmm_setup_queue_priorities(priv, pWmmParamIe);
+ }
+ }
+ if (tlv_type == TLV_TYPE_UAP_PKT_FWD_CTL) {
+ DBG_HEXDUMP(MCMD_D, "pkt_fwd tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->pkt_fwd = *((t_u8 *) tlv + sizeof(MrvlIEtypesHeader_t));
+ PRINTM(MCMND, "pkt_fwd FW: 0x%x\n", priv->pkt_fwd);
+ if (priv->pkt_fwd & PKT_FWD_FW_BIT)
+ priv->pkt_fwd = MFALSE;
+ else
+ priv->pkt_fwd |= PKT_FWD_ENABLE_BIT;
+ PRINTM(MCMND, "pkt_fwd DRV: 0x%x\n", priv->pkt_fwd);
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ if (priv->wmm_enabled == MFALSE) {
+ /* Since WMM is not enabled, setup the queues with the defaults */
+ wlan_wmm_setup_queues(priv);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will update WAPI PN in statation assoc event
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return MFALSE
+ */
+static t_u32
+wlan_update_wapi_info_tlv(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u32 ret = MFALSE;
+ t_u16 tlv_type, tlv_len;
+ t_u32 tx_pn[4];
+ t_u32 i = 0;
+ int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv = (MrvlIEtypesHeader_t *)
+ (pevent->pbuf + pevent->data_offset + ASSOC_EVENT_FIX_SIZE);
+ MrvlIEtypes_wapi_info_t *wapi_tlv = MNULL;
+
+ ENTER();
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_AP_WAPI_INFO) {
+ wapi_tlv = (MrvlIEtypes_wapi_info_t *) tlv;
+ DBG_HEXDUMP(MCMD_D, "Fw:multicast_PN", wapi_tlv->multicast_PN,
+ PN_SIZE);
+ memcpy(priv->adapter, (t_u8 *) tx_pn, wapi_tlv->multicast_PN,
+ PN_SIZE);
+ for (i = 0; i < 4; i++)
+ tx_pn[i] = mlan_ntohl(tx_pn[i]);
+ memcpy(priv->adapter, wapi_tlv->multicast_PN, (t_u8 *) tx_pn,
+ PN_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Host:multicast_PN", wapi_tlv->multicast_PN,
+ PN_SIZE);
+ break;
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function send sta_assoc_event to moal
+ * payload with sta mac address and assoc ie.
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to mlan_event buffer
+ * @param pbuf A pointer to mlan_buffer which has event content.
+ *
+ * @return MFALSE
+ */
+static t_u32
+wlan_process_sta_assoc_event(pmlan_private priv, mlan_event * pevent,
+ pmlan_buffer pmbuf)
+{
+ t_u32 ret = MFALSE;
+ t_u16 tlv_type, tlv_len;
+ t_u16 frame_control, frame_sub_type = 0;
+ t_u8 *assoc_req_ie = MNULL;
+ t_u8 ie_len = 0, assoc_ie_len = 0;
+ int tlv_buf_left = pmbuf->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv = (MrvlIEtypesHeader_t *)
+ (pmbuf->pbuf + pmbuf->data_offset + ASSOC_EVENT_FIX_SIZE);
+ MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
+
+ ENTER();
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_CONNECT;
+ pevent->bss_index = priv->bss_index;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(priv->adapter, pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + 6, pevent->event_len);
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_UAP_MGMT_FRAME) {
+ mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *) tlv;
+ memcpy(priv->adapter, &frame_control,
+ (t_u8 *) & (mgmt_tlv->frame_control), sizeof(frame_control));
+ frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(frame_control);
+ if ((mgmt_tlv->frame_control.type == 0) &&
+ ((frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
+ (frame_sub_type == SUBTYPE_REASSOC_REQUEST))) {
+
+ if (frame_sub_type == SUBTYPE_ASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_AssocRqst_t);
+ else if (frame_sub_type == SUBTYPE_REASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_ReAssocRqst_t);
+
+ ie_len = tlv_len - sizeof(IEEEtypes_FrameCtl_t) - assoc_ie_len;
+ assoc_req_ie =
+ (t_u8 *) tlv + sizeof(MrvlIETypes_MgmtFrameSet_t) +
+ assoc_ie_len;
+ memcpy(priv->adapter, pevent->event_buf + pevent->event_len,
+ assoc_req_ie, ie_len);
+ pevent->event_len += ie_len;
+ break;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ PRINTM(MEVENT, "STA assoc event len=%d\n", pevent->event_len);
+ DBG_HEXDUMP(MCMD_D, "STA assoc event", pevent->event_buf,
+ pevent->event_len);
+ wlan_recv_event(priv, pevent->event_id, pevent);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_SOFT_RESET:
+ case HOST_CMD_APCMD_BSS_STOP:
+ case HOST_CMD_APCMD_BSS_START:
+ case HOST_CMD_APCMD_SYS_INFO:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HOST_CMD_APCMD_SYS_CONFIGURE:
+ ret = wlan_uap_cmd_sys_configure(pmpriv, cmd_ptr, cmd_action,
+ (pmlan_ioctl_req) pioctl_buf,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret =
+ wlan_cmd_enh_power_mode(pmpriv, cmd_ptr, cmd_action,
+ (t_u16) cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ ret = wlan_cmd_sdio_gpio_int(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status = WlanHardwareStatusInitializing;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_cmd_cfg_data(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_uap_cmd_snmp_mib(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ (pmlan_ioctl_req) pioctl_buf, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HOST_CMD_APCMD_STA_DEAUTH:
+ ret = wlan_uap_cmd_sta_deauth(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret =
+ wlan_uap_cmd_key_material(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret =
+ wlan_uap_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (hs_config_param *) pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_cmd_tx_bf_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ if (pdata_buf)
+ cmd_ptr->params.bss_mode.con_type = *(t_u8 *) pdata_buf;
+ else
+ cmd_ptr->params.bss_mode.con_type = BSS_MODE_WIFIDIRECT_GO;
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SET_BSS_MODE) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+#endif
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8) (*((t_u32 *) pdata_buf));
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.rx_mgmt_ind.action = wlan_cpu_to_le16(cmd_action);
+ cmd_ptr->params.rx_mgmt_ind.mgmt_subtype_mask =
+ (t_u32) (*((t_u32 *) pdata_buf));
+ cmd_ptr->size = wlan_cpu_to_le16(sizeof(t_u32) + S_DS_GEN);
+ break;
+ case HostCmd_CMD_CFG_TX_DATA_PAUSE:
+ ret = wlan_uap_cmd_txdatapause(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret =
+ wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret =
+ wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_cmd_wifi_direct_mode(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret =
+ wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the AP mode command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *) pioctl;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int ctr;
+
+ ENTER();
+
+ /* If the command is not successful, cleanup and return failure */
+ if (resp->result != HostCmd_RESULT_OK) {
+ uap_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HOST_CMD_APCMD_BSS_STOP:
+ pmpriv->uap_bss_started = MFALSE;
+ wlan_11h_check_update_radar_det_state(pmpriv);
+
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ break;
+ case HOST_CMD_APCMD_BSS_START:
+ if (pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ break;
+ case HOST_CMD_APCMD_SYS_RESET:
+ ret = wlan_uap_ret_sys_reset(pmpriv, resp, pioctl_buf);
+
+ pmpriv->uap_bss_started = MFALSE;
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ break;
+ case HOST_CMD_APCMD_SYS_INFO:
+ break;
+ case HOST_CMD_APCMD_SYS_CONFIGURE:
+ ret = wlan_uap_ret_sys_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_enh_power_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_uap_ret_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HOST_CMD_APCMD_STA_DEAUTH:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ break;
+ case HOST_CMD_APCMD_STA_LIST:
+ ret = wlan_uap_ret_sta_list(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_ret_cfg_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ pmadapter->tx_buf_size =
+ (t_u16) wlan_le16_to_cpu(resp->params.tx_buf.buff_size);
+ pmadapter->tx_buf_size =
+ (pmadapter->tx_buf_size / MLAN_SDIO_BLOCK_SIZE) *
+ MLAN_SDIO_BLOCK_SIZE;
+ pmadapter->curr_tx_buf_size = pmadapter->tx_buf_size;
+ pmadapter->mp_end_port =
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port);
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+ for (ctr = 1; ctr <= MAX_PORT - pmadapter->mp_end_port; ctr++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - ctr));
+ }
+ pmadapter->curr_wr_port = 1;
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port),
+ pmadapter->mp_data_port_mask);
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_ret_tx_bf_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ ret = wlan_ret_rx_mgmt_ind(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_TX_DATA_PAUSE:
+ ret = wlan_uap_ret_txdatapause(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_ret_wifi_direct_mode(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_process_event(IN t_void * priv)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u8 *event_buf = MNULL;
+ mlan_event *pevent = MNULL;
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ sta_node *sta_ptr = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+
+ /* Allocate memory for event buffer */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF,
+ &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ if (pmbuf)
+ pmbuf->status_code = MLAN_ERROR_NO_MEM;
+ goto done;
+ }
+ pevent = (pmlan_event) event_buf;
+ memset(pmadapter, &pevent->event_id, 0, sizeof(pevent->event_id));
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ pmbuf->data_len > sizeof(eventcause))
+ DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+
+ switch (eventcause) {
+ case EVENT_MICRO_AP_BSS_START:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_START\n");
+ pmpriv->uap_bss_started = MTRUE;
+ memcpy(pmadapter, pmpriv->curr_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH);
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_START;
+ wlan_check_uap_capability(pmpriv, pmbuf);
+ break;
+ case EVENT_MICRO_AP_BSS_ACTIVE:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_ACTIVE\n");
+ pmpriv->media_connected = MTRUE;
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE;
+ break;
+ case EVENT_MICRO_AP_BSS_IDLE:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_IDLE\n");
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_IDLE;
+ pmpriv->media_connected = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_delete_station_list(pmpriv);
+ break;
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE \n");
+ PRINTM(MEVENT, "||");
+ /* Handle unexpected PS AWAKE event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ break;
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM(MEVENT, "__");
+ /* Handle unexpected PS SLEEP event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+ wlan_check_ps_cond(pmadapter);
+ break;
+ case EVENT_MICRO_AP_STA_ASSOC:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_STA_ASSOC\n");
+ wlan_process_sta_assoc_event(pmpriv, pevent, pmbuf);
+ memcpy(pmadapter, sta_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH);
+ sta_ptr = wlan_add_station_entry(pmpriv, sta_addr);
+ if (pmpriv->is_11n_enabled) {
+ wlan_check_sta_capability(pmpriv, pmbuf, sta_ptr);
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (sta_ptr->is_11n_enabled)
+ sta_ptr->ampdu_sta[i] = pmpriv->aggr_prio_tbl[i].ampdu_user;
+ else
+ sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
+ }
+ memset(pmadapter, sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
+ }
+ if (pmpriv->sec_info.wapi_enabled)
+ wlan_update_wapi_info_tlv(pmpriv, pmbuf);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_MICRO_AP_STA_DEAUTH:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_STA_DEAUTH\n");
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_len = pmbuf->data_len - 4;
+ /* skip event length field */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + 4, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ memcpy(pmadapter, sta_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH);
+ if (pmpriv->is_11n_enabled) {
+ wlan_cleanup_reorder_tbl(pmpriv, sta_addr);
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmpriv->wmm.ra_list_spinlock);
+ wlan_11n_cleanup_txbastream_tbl(pmpriv, sta_addr);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->wmm.ra_list_spinlock);
+ }
+ wlan_wmm_delete_peer_ralist(pmpriv, sta_addr);
+ wlan_delete_station_entry(pmpriv, sta_addr);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_HS_CFG_ENH, 0, 0, MNULL,
+ MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body);
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIMEOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ wlan_11n_ba_stream_timeout(pmpriv,
+ (HostCmd_DS_11N_BATIMEOUT *) pmadapter->
+ event_body);
+ break;
+ case EVENT_RXBA_SYNC:
+ PRINTM(MEVENT, "EVENT: RXBA_SYNC\n");
+ wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
+ pmbuf->data_len - sizeof(eventcause));
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pmadapter->tx_buf_size =
+ MIN(pmadapter->curr_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
+ break;
+ case EVENT_TX_DATA_PAUSE:
+ PRINTM(MEVENT, "EVENT: TX_DATA_PAUSE\n");
+ wlan_process_tx_pause_event(priv, pmbuf);
+ break;
+ case EVENT_RADAR_DETECTED:
+ PRINTM(MEVENT, "EVENT: Radar Detected\n");
+
+ /* Send as passthru first, this event can cause other events */
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ pevent->event_id = 0; // clear to avoid resending at end of fcn
+
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage = RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(pmadapter);
+ } else {
+ PRINTM(MEVENT, "Ignore Event Radar Detected - handling"
+ " already in progress.\n");
+ }
+ break;
+ case EVENT_CHANNEL_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ /* Setup event buffer */
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ /* Copy event data */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause),
+ pevent->event_len);
+ /* Handle / pass event data, and free buffer */
+ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent);
+
+ /* Send up this Event to unblock MOAL waitqueue */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
+ PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pevent->event_id = MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED;
+ break;
+#endif
+ default:
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ }
+
+ if (pevent->event_id) {
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ }
+ done:
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_bss flag for first BSS
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_init_cmd(IN t_void * priv, IN t_u8 first_bss)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = (pmlan_private) priv;
+ t_u16 last_cmd = 0;
+
+ ENTER();
+
+ if (first_bss) {
+ if (wlan_adapter_init_cmd(pmpriv->adapter) == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ last_cmd = HOST_CMD_APCMD_SYS_CONFIGURE;
+ /** set last_init_cmd */
+ if (last_cmd) {
+ pmpriv->adapter->last_init_cmd = last_cmd;
+ ret = MLAN_STATUS_PENDING;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
new file mode 100644
index 000000000000..f71a222f4f48
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
@@ -0,0 +1,1393 @@
+/** @file mlan_uap_ioctl.c
+ *
+ * @brief This file contains the handling of AP mode ioctls
+ *
+ * Copyright (C) 2009-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:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_sdio.h"
+#include "mlan_11n.h"
+#include "mlan_fw.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern t_u8 tos_to_tid_inv[];
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Stop BSS
+ *
+ * @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_uap_bss_ioctl_stop(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish BSS IOCTL START
+ * Not to be called directly to initiate bss_start
+ *
+ * @param priv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_bss_ioctl_start
+ */
+static mlan_status
+wlan_uap_callback_bss_ioctl_start(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ t_u8 old_channel;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ /*
+ * Check if the region and channel requires we check for radar.
+ */
+ if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(pmpriv, puap_state_chan_cb->channel)) {
+ /* first check if channel is under NOP */
+ if (wlan_11h_is_channel_under_nop(pmpriv->adapter,
+ puap_state_chan_cb->channel)) {
+ /* recently we've seen radar on this channel */
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* Check cached radar check on the channel */
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret =
+ wlan_11h_check_chan_report(pmpriv, puap_state_chan_cb->channel);
+
+ /* Found radar: try to switch to a non-dfs channel */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ old_channel = puap_state_chan_cb->channel;
+ ret =
+ wlan_11h_switch_non_dfs_chan(pmpriv,
+ &puap_state_chan_cb->channel);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ ret = wlan_uap_set_channel(pmpriv,
+ pmpriv->uap_state_chan_cb.
+ band_config,
+ puap_state_chan_cb->channel);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG, "Radar found on channel %d,"
+ "switch to new channel %d.\n",
+ old_channel, puap_state_chan_cb->channel);
+ } else {
+ PRINTM(MMSG, "Radar found on channel %d,"
+ " switch to new channel %d failed.\n",
+ old_channel, puap_state_chan_cb->channel);
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->
+ pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ }
+ } else {
+ PRINTM(MMSG,
+ "Radar found on channel %d, no switch channel available.\n",
+ old_channel);
+ /* No command sent with the ioctl, need manually signal
+ completion */
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ }
+ } else {
+ PRINTM(MINFO, "No Radar found on channel %d\n",
+ puap_state_chan_cb->channel);
+ }
+ }
+
+ /* else okay to send command: not DFS channel or no radar */
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) puap_state_chan_cb->pioctl_req_curr,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ done:
+ puap_state_chan_cb->pioctl_req_curr = MNULL; // prevent re-use
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+/**
+ * @sa wlan_uap_callback_bss_ioctl_start
+ */
+static mlan_status
+wlan_uap_bss_ioctl_start(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* First check channel report, defer BSS_START CMD to callback. */
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of bss_start handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_bss_ioctl_start;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset BSS
+ *
+ * @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_uap_bss_ioctl_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u8 i = 0;
+
+ ENTER();
+
+ /*
+ * Reset any uap private parameters here
+ */
+ for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) {
+ memset(pmadapter, &pmpriv->mgmt_ie[i], 0, sizeof(custom_ie));
+ }
+ pmpriv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+ pmpriv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ pmpriv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ pmpriv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ pmpriv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
+ pmpriv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+ }
+
+ /* hs_configured, hs_activated are reset by main loop */
+ pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
+ pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
+ pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @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_uap_bss_ioctl_mac_address(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ memcpy(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Uap statistics
+ *
+ * @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_uap_get_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get AP config
+ *
+ * @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_uap_bss_ioctl_config(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ 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, HOST_CMD_APCMD_SYS_CONFIGURE,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief deauth sta
+ *
+ * @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_uap_bss_ioctl_deauth_sta(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & bss->param.deauth_param);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get station list
+ *
+ * @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_uap_get_sta_list(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_STA_LIST,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief soft_reset
+ *
+ * @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_uap_misc_ioctl_soft_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SOFT_RESET,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Tx data pause
+ *
+ * @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_uap_misc_ioctl_txdatapause(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_CFG_TX_DATA_PAUSE,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &(pmisc->param.tx_datapause));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Power mode
+ *
+ * @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_uap_pm_ioctl_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u32 cmd_oid = 0;
+
+ ENTER();
+
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pm->param.ps_mgmt.ps_mode == PS_MODE_INACTIVITY) {
+ cmd_action = EN_AUTO_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS;
+ } else if (pm->param.ps_mgmt.ps_mode == PS_MODE_PERIODIC_DTIM) {
+ cmd_action = EN_AUTO_PS;
+ cmd_oid = BITMAP_UAP_DTIM_PS;
+ } else {
+ cmd_action = DIS_AUTO_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
+ }
+ } else {
+ cmd_action = GET_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
+ }
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ cmd_action, cmd_oid, (t_void *) pioctl_req,
+ (t_void *) & pm->param.ps_mgmt);
+ if ((ret == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_SET) && (cmd_action == DIS_AUTO_PS)) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, MNULL, MNULL);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_set_wapi_ie(mlan_private * priv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc->param.gen_ie.len) {
+ if (misc->param.gen_ie.len > sizeof(priv->wapi_ie)) {
+ PRINTM(MWARN, "failed to copy WAPI IE, too big \n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->adapter, priv->wapi_ie, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ priv->wapi_ie_len = misc->param.gen_ie.len;
+ PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie, priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = misc->param.gen_ie.len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(priv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set generic IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_misc_ioctl_gen_ie(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_misc_cfg *misc = MNULL;
+ IEEEtypes_VendorHeader_t *pvendor_ie = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ if ((misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE) &&
+ (pioctl_req->action == MLAN_ACT_SET)) {
+ if (misc->param.gen_ie.len) {
+ pvendor_ie =
+ (IEEEtypes_VendorHeader_t *) misc->param.gen_ie.ie_data;
+ if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
+ }
+ } else {
+ /* clear WAPI IE */
+ ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @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_uap_sec_ioctl_wapi_enable(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_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE) {
+ memset(pmpriv->adapter, pmpriv->wapi_ie, 0,
+ sizeof(pmpriv->wapi_ie));
+ pmpriv->wapi_ie_len = 0;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", pmpriv->wapi_ie_len,
+ pmpriv->wapi_ie[0]);
+ pmpriv->sec_info.wapi_enabled = MFALSE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encrypt key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_sec_ioctl_set_encrypt_key(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_sec_cfg *sec = MNULL;
+
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_SET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!sec->param.encrypt_key.key_len) {
+ PRINTM(MCMND, "Skip set key with key_len = 0\n");
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @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_uap_get_bss_info(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* BSSID */
+ memcpy(pmadapter, &info->param.bss_info.bssid, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCES/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_pm_ioctl_deepsleep(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_pm_cfg *pm = MNULL;
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmadapter->is_deep_sleep) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = pmadapter->idle_time;
+ } else
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ } else {
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ PRINTM(MMSG, "uAP already in deep sleep mode\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ auto_ds == DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ mode = EN_AUTO_PS;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ } else {
+ mode = DIS_AUTO_PS;
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "Auto Deep Sleep: off\n");
+ }
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ idletime)
+ auto_ds.idletime =
+ ((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ idletime;
+ else
+ auto_ds.idletime = pmadapter->idle_time;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ (t_u16) mode,
+ BITMAP_AUTO_DS, (t_void *) pioctl_req, &auto_ds);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set SNMP MIB for 11D
+ *
+ * @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_uap_snmp_mib_11d(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_snmp_mib *snmp = MNULL;
+ state_11d_t flag;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
+ PRINTM(MIOCTL,
+ "11D setting cannot be changed while UAP bss is started.\n");
+ pioctl_req->data_read_written = 0;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ flag = (snmp->param.oid_value) ? ENABLE_11D : DISABLE_11D;
+
+ ret = wlan_11d_enable(pmpriv, (t_void *) pioctl_req, flag);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish domain_info handling
+ * Not to be called directly to initiate domain_info setting.
+ *
+ * @param pmpriv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_domain_info
+ */
+static mlan_status
+wlan_uap_callback_domain_info(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ mlan_ds_11d_cfg *cfg11d;
+ t_u8 band;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ cfg11d = (mlan_ds_11d_cfg *) puap_state_chan_cb->pioctl_req_curr->pbuf;
+ band =
+ (puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) ? BAND_A : BAND_B;
+
+ ret =
+ wlan_11d_handle_uap_domain_info(pmpriv, band, cfg11d->param.domain_tlv,
+ puap_state_chan_cb->pioctl_req_curr);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ puap_state_chan_cb->pioctl_req_curr = MNULL; // prevent re-use
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Domain Info for 11D
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_domain_info
+ */
+static mlan_status
+wlan_uap_domain_info(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];
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN 11d_cfg IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
+ PRINTM(MIOCTL,
+ "Domain_info cannot be changed while UAP bss is started.\n");
+ pioctl_req->data_read_written = 0;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of domain_info handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback = wlan_uap_callback_domain_info;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish 11H channel check handling.
+ * Not to be called directly to initiate channel check.
+ *
+ * @param priv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_SUCCESS/PENDING --success, otherwise fail
+ * @sa wlan_uap_11h_channel_check_req
+ */
+static mlan_status
+wlan_uap_callback_11h_channel_check_req(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ /* keep copy as local variable */
+ pmlan_ioctl_req pioctl = puap_state_chan_cb->pioctl_req_curr;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+ /* clear early to avoid race condition */
+ puap_state_chan_cb->pioctl_req_curr = MNULL;
+
+ /*
+ * Check if the region and channel requires a channel availability
+ * check.
+ */
+ if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(pmpriv, puap_state_chan_cb->channel) &&
+ !wlan_11h_is_channel_under_nop(pmpriv->adapter,
+ puap_state_chan_cb->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);
+
+ /* Check for radar on the channel */
+ ret = wlan_11h_issue_radar_detect(pmpriv,
+ pioctl, puap_state_chan_cb->channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* No command sent with the ioctl, need manually signal completion */
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
+ pioctl, MLAN_STATUS_FAILURE);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h uap start channel check
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_11h_channel_check_req
+ */
+static mlan_status
+wlan_uap_11h_channel_check_req(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];
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
+ PRINTM(MWARN, "MLAN 11h_cfg IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of 11H channel check handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_11h_channel_check_req;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish 11H handling
+ * Not to be called directly to initiate 11H setting.
+ *
+ * @param pmpriv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_snmp_mib_11h
+ */
+static mlan_status
+wlan_uap_callback_snmp_mib_11h(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ mlan_ds_snmp_mib *snmp;
+ t_bool enable_11h;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ snmp = (mlan_ds_snmp_mib *) puap_state_chan_cb->pioctl_req_curr->pbuf;
+ enable_11h = (snmp->param.oid_value) ? MTRUE : MFALSE;
+
+ if (enable_11h) {
+ if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(pmpriv,
+ puap_state_chan_cb->channel)) {
+ if (!wlan_11h_is_master_radar_det_active(pmpriv))
+ wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ }
+ }
+
+ ret =
+ wlan_11h_activate(pmpriv,
+ (t_void *) puap_state_chan_cb->pioctl_req_curr,
+ enable_11h);
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ puap_state_chan_cb->pioctl_req_curr = MNULL; // prevent re-use
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set SNMP MIB for 11H
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_snmp_mib_11h
+ */
+static mlan_status
+wlan_uap_snmp_mib_11h(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_snmp_mib *snmp = MNULL;
+ t_bool enable;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ enable = (snmp->param.oid_value) ? MTRUE : MFALSE;
+
+ if (enable) {
+ /* first enable 11D if it is not enabled */
+ if (!wlan_11d_is_enabled(pmpriv)) {
+ ret = wlan_11d_enable(pmpriv, MNULL, ENABLE_11D);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Failed to first enable 11D before enabling 11H.\n");
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of 11H handling (and radar detect if DFS chan) */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_snmp_mib_11h;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Issue CMD to UAP firmware to get current channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_uap_get_channel(IN pmlan_private pmpriv)
+{
+ MrvlIEtypes_channel_band_t tlv_chan_band;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
+ tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
+ tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t)
+ - sizeof(MrvlIEtypesHeader_t);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, &tlv_chan_band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue CMD to UAP firmware to set current channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param uap_band_cfg UAP band configuration
+ * @param channel New channel
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_uap_set_channel(IN pmlan_private pmpriv,
+ IN t_u8 uap_band_cfg, IN t_u8 channel)
+{
+ MrvlIEtypes_channel_band_t tlv_chan_band;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
+ tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
+ tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t)
+ - sizeof(MrvlIEtypesHeader_t);
+ tlv_chan_band.band_config = uap_band_cfg;
+ tlv_chan_band.channel = channel;
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &tlv_chan_band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue CMD to UAP firmware to get current beacon and dtim periods
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_uap_get_beacon_dtim(IN pmlan_private pmpriv)
+{
+ t_u8 tlv_buffer[sizeof(MrvlIEtypes_beacon_period_t) +
+ sizeof(MrvlIEtypes_dtim_period_t)];
+ MrvlIEtypes_beacon_period_t *ptlv_beacon_pd;
+ MrvlIEtypes_dtim_period_t *ptlv_dtim_pd;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(pmpriv->adapter, &tlv_buffer, 0, sizeof(tlv_buffer));
+ ptlv_beacon_pd = (MrvlIEtypes_beacon_period_t *) tlv_buffer;
+ ptlv_beacon_pd->header.type = TLV_TYPE_UAP_BEACON_PERIOD;
+ ptlv_beacon_pd->header.len = sizeof(MrvlIEtypes_beacon_period_t)
+ - sizeof(MrvlIEtypesHeader_t);
+
+ ptlv_dtim_pd = (MrvlIEtypes_dtim_period_t *) (tlv_buffer
+ +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ ptlv_dtim_pd->header.type = TLV_TYPE_UAP_DTIM_PERIOD;
+ ptlv_dtim_pd->header.len = sizeof(MrvlIEtypes_dtim_period_t)
+ - sizeof(MrvlIEtypesHeader_t);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, tlv_buffer);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN uap ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_ops_uap_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_ds_snmp_mib *snmp = MNULL;
+ mlan_ds_11d_cfg *cfg11d = MNULL;
+ mlan_ds_11h_cfg *cfg11h = MNULL;
+ mlan_ds_radio_cfg *radiocfg = MNULL;
+ mlan_ds_rate *rate = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_BSS:
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR)
+ status = wlan_uap_bss_ioctl_mac_address(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_BSS_STOP)
+ status = wlan_uap_bss_ioctl_stop(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_BSS_START)
+ status = wlan_uap_bss_ioctl_start(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_BSS_CONFIG)
+ status = wlan_uap_bss_ioctl_config(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_DEAUTH_STA)
+ status = wlan_uap_bss_ioctl_deauth_sta(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_BSS_RESET)
+ status = wlan_uap_bss_ioctl_reset(pmadapter, pioctl_req);
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ else if (bss->sub_command == MLAN_OID_BSS_ROLE)
+ status = wlan_bss_ioctl_bss_role(pmadapter, pioctl_req);
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (bss->sub_command == MLAN_OID_WIFI_DIRECT_MODE)
+ status = wlan_bss_ioctl_wifi_direct_mode(pmadapter, pioctl_req);
+#endif
+ break;
+ case MLAN_IOCTL_GET_INFO:
+ pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
+ if (pget_info->sub_command == MLAN_OID_GET_VER_EXT)
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_DEBUG_INFO)
+ status = wlan_get_info_debug_info(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_STATS)
+ status = wlan_uap_get_stats(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_UAP_STA_LIST)
+ status = wlan_uap_get_sta_list(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_BSS_INFO)
+ status = wlan_uap_get_bss_info(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_FW_INFO) {
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ memcpy(pmadapter, &pget_info->param.fw_info.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+ pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
+ pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
+ pget_info->param.fw_info.hw_dev_mcs_support =
+ pmadapter->hw_dev_mcs_support;
+ }
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc->sub_command == MLAN_OID_MISC_INIT_SHUTDOWN)
+ status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_SOFT_RESET)
+ status = wlan_uap_misc_ioctl_soft_reset(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_HOST_CMD)
+ status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GEN_IE)
+ status = wlan_uap_misc_ioctl_gen_ie(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)
+ status =
+ wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MTRUE);
+ if (misc->sub_command == MLAN_OID_MISC_TX_DATAPAUSE)
+ status = wlan_uap_misc_ioctl_txdatapause(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RX_MGMT_IND)
+ status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
+#ifdef DEBUG_LEVEL1
+ if (misc->sub_command == MLAN_OID_MISC_DRVDBG)
+ status = wlan_set_drvdbg(pmadapter, pioctl_req);
+#endif
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pm->sub_command == MLAN_OID_PM_CFG_PS_MODE)
+ status = wlan_uap_pm_ioctl_mode(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_CFG_DEEP_SLEEP)
+ status = wlan_uap_pm_ioctl_deepsleep(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_CFG_HS_CFG) {
+ status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
+ }
+ if (pm->sub_command == MLAN_OID_PM_INFO) {
+ status = wlan_get_pm_info(pmadapter, pioctl_req);
+ }
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11D)
+ status = wlan_uap_snmp_mib_11d(pmadapter, pioctl_req);
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11H)
+ status = wlan_uap_snmp_mib_11h(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (sec->sub_command == MLAN_OID_SEC_CFG_ENCRYPT_KEY)
+ status = wlan_uap_sec_ioctl_set_encrypt_key(pmadapter, pioctl_req);
+ if (sec->sub_command == MLAN_OID_SEC_CFG_WAPI_ENABLED)
+ status = wlan_uap_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ cfg11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ if (cfg11d->sub_command == MLAN_OID_11D_DOMAIN_INFO)
+ status = wlan_uap_domain_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ cfg11h = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+ if (cfg11h->sub_command == MLAN_OID_11H_CHANNEL_CHECK)
+ status = wlan_uap_11h_channel_check_req(pmadapter, pioctl_req);
+#if defined(DFS_TESTING_SUPPORT)
+ if (cfg11h->sub_command == MLAN_OID_11H_DFS_TESTING)
+ status = wlan_11h_ioctl_dfs_testing(pmadapter, pioctl_req);
+#endif
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ radiocfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (radiocfg->sub_command == MLAN_OID_RADIO_CTRL)
+ status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (radiocfg->sub_command == MLAN_OID_REMAIN_CHAN_CFG)
+ status = wlan_radio_ioctl_remain_chan_cfg(pmadapter, pioctl_req);
+#endif
+ if (radiocfg->sub_command == MLAN_OID_ANT_CFG)
+ status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG)
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
new file mode 100644
index 000000000000..590def325f27
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
@@ -0,0 +1,556 @@
+/** @file mlan_uap_txrx.c
+ *
+ * @brief This file contains AP mode transmit and receive functions
+ *
+ * Copyright (C) 2009-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:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_sdio.h"
+#include "mlan_wmm.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_upload_uap_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ UapRxPD *prx_pd;
+ ENTER();
+ prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+
+ /* Chop off RxPD */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->pparent = MNULL;
+
+ DBG_HEXDUMP(MDAT_D, "uAP RxPD", (t_u8 *) prx_pd,
+ MIN(sizeof(UapRxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
+ ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "uAP Rx Error: moal_recv_packet returned error\n");
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ }
+
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ LEAVE();
+
+ return ret;
+
+}
+
+/**
+ * @brief This function will check if unicast packet need be dropped
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return MLAN_STATUS_FAILURE -- drop packet, otherwise forward to network stack
+ */
+static mlan_status
+wlan_check_unicast_packet(mlan_private * priv, t_u8 * mac)
+{
+ int j;
+ sta_node *sta_ptr = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_private pmpriv = MNULL;
+ t_u8 pkt_type = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ for (j = 0; j < MLAN_MAX_BSS_NUM; ++j) {
+ if ((pmpriv = pmadapter->priv[j])) {
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ continue;
+ sta_ptr = wlan_get_station_entry(pmpriv, mac);
+ if (sta_ptr) {
+ if (pmpriv == priv)
+ pkt_type = PKT_INTRA_UCAST;
+ else
+ pkt_type = PKT_INTER_UCAST;
+ break;
+ }
+ }
+ }
+ if ((pkt_type == PKT_INTRA_UCAST) && (priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) {
+ PRINTM(MDATA, "Drop INTRA_UCAST packet\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else if ((pkt_type == PKT_INTER_UCAST) &&
+ (priv->pkt_fwd & PKT_FWD_INTER_UCAST)) {
+ PRINTM(MDATA, "Drop INTER_UCAST packet\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function fill the txpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *
+wlan_ops_uap_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ UapTxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+ ENTER();
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "uAP Tx Error: Invalid packet length: %d\n",
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ memcpy(pmpriv->adapter, &pkt_type, pmbuf->pbuf + pmbuf->data_offset,
+ sizeof(pkt_type));
+ memcpy(pmpriv->adapter, &tx_control,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ sizeof(tx_control));
+ pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
+ pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
+ }
+ if (pmbuf->data_offset < (sizeof(UapTxPD) + INTF_HEADER_LEN +
+ DMA_ALIGNMENT)) {
+ PRINTM(MERROR, "not enough space for UapTxPD: len=%d, offset=%d\n",
+ pmbuf->data_len, pmbuf->data_offset);
+ DBG_HEXDUMP(MDAT_D, "drop pkt", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr =
+ pmbuf->pbuf + pmbuf->data_offset - sizeof(UapTxPD) - INTF_HEADER_LEN;
+ head_ptr = (t_u8 *) ((t_ptr) head_ptr & ~((t_ptr) (DMA_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (UapTxPD *) (head_ptr + INTF_HEADER_LEN);
+ memset(pmpriv->adapter, plocal_tx_pd, 0, sizeof(UapTxPD));
+
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
+ plocal_tx_pd->bss_type = pmpriv->bss_type;
+
+ plocal_tx_pd->tx_pkt_length = (t_u16) pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8) pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority < NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control
+ = pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset =
+ (t_u16) ((t_ptr) pmbuf->pbuf + pmbuf->data_offset -
+ (t_ptr) plocal_tx_pd);
+
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ plocal_tx_pd->tx_pkt_type = (t_u16) pkt_type;
+ plocal_tx_pd->tx_control = tx_control;
+ }
+ uap_endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = (t_u32) ((t_ptr) head_ptr - (t_ptr) pmbuf->pbuf);
+ pmbuf->data_len -= pmbuf->data_offset;
+
+ done:
+ LEAVE();
+ return head_ptr;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_process_rx_packet(IN t_void * adapter, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ UapRxPD *prx_pd;
+ wlan_mgmt_pkt *puap_pkt_hdr = MNULL;
+
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ uap_endian_convert_RxPD(prx_pd);
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) >
+ (t_u16) pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n", pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to forwarded to app as an
+ event */
+ puap_pkt_hdr =
+ (wlan_mgmt_pkt *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+ puap_pkt_hdr->frm_len = wlan_le16_to_cpu(puap_pkt_hdr->frm_len);
+ if ((puap_pkt_hdr->wlan_header.
+ frm_ctl & IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *) & puap_pkt_hdr->wlan_header,
+ puap_pkt_hdr->frm_len +
+ sizeof(wlan_mgmt_pkt) -
+ sizeof(puap_pkt_hdr->frm_len));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+
+ pmbuf->priority = prx_pd->priority;
+ memcpy(pmadapter, ta, prx_pkt->eth803_hdr.src_addr, MLAN_MAC_ADDR_LENGTH);
+ if ((rx_pkt_type != PKT_TYPE_BAR) && (prx_pd->priority < MAX_NUM_TID)) {
+ if ((sta_ptr = wlan_get_station_entry(priv, ta)))
+ sta_ptr->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ }
+ /* check if UAP enable 11n */
+ if (!priv->is_11n_enabled ||
+ (!wlan_11n_get_rxreorder_tbl
+ ((mlan_private *) priv, prx_pd->priority, ta)
+ && (prx_pd->rx_pkt_type != PKT_TYPE_AMSDU)
+ )) {
+ if (priv->pkt_fwd)
+ wlan_process_uap_rx_packet(priv, pmbuf);
+ else
+ wlan_upload_uap_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+ /* Reorder and send to OS */
+ if ((ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num,
+ prx_pd->priority, ta,
+ (t_u8) prx_pd->rx_pkt_type,
+ (void *) pmbuf))
+ || (rx_pkt_type == PKT_TYPE_BAR)) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ done:
+ if (priv->is_11n_enabled &&
+ (pmadapter->pending_bridge_pkts >= RX_MED_THRESHOLD))
+ wlan_send_delba_to_all_in_reorder_tbl(priv);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer or send back to firmware
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_uap_recv_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_buffer newbuf = MNULL;
+
+ ENTER();
+
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) pmbuf->pbuf + pmbuf->data_offset);
+
+ DBG_HEXDUMP(MDAT_D, "uap_recv_packet", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+
+ PRINTM(MDATA, "AMSDU dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0], prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2], prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4], prx_pkt->eth803_hdr.dest_addr[5]);
+
+ /* don't do packet forwarding in disconnected state */
+ if ((priv->media_connected == MFALSE) ||
+ (pmbuf->data_len > MV_ETH_FRAME_LEN))
+ goto upload;
+
+ if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
+ if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
+ /* Multicast pkt */
+ if ((newbuf =
+ wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MTRUE))) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
+ pmadapter->pending_bridge_pkts++;
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data */
+ memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
+ newbuf->data_len = pmbuf->data_len;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ }
+ }
+ } else {
+ if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
+ (wlan_get_station_entry(priv, prx_pkt->eth803_hdr.dest_addr))) {
+ /* Intra BSS packet */
+ if ((newbuf =
+ wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MTRUE))) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
+ pmadapter->pending_bridge_pkts++;
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data */
+ memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
+ newbuf->data_len = pmbuf->data_len;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ }
+ goto done;
+ } else if (MLAN_STATUS_FAILURE ==
+ wlan_check_unicast_packet(priv,
+ prx_pkt->eth803_hdr.dest_addr)) {
+ /* drop packet */
+ PRINTM(MDATA, "Drop AMSDU dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0],
+ prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2],
+ prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4],
+ prx_pkt->eth803_hdr.dest_addr[5]);
+ goto done;
+ }
+ }
+ upload:
+ /** send packet to moal */
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer or send back to firmware
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_uap_rx_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ UapRxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_buffer newbuf = MNULL;
+
+ ENTER();
+
+ prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ DBG_HEXDUMP(MDAT_D, "uAP RxPD", prx_pd,
+ MIN(sizeof(UapRxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
+ ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+ PRINTM(MDATA, "Rx dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0], prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2], prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4], prx_pkt->eth803_hdr.dest_addr[5]);
+
+ /* don't do packet forwarding in disconnected state */
+ /* don't do packet forwarding when packet > 1514 */
+ if ((priv->media_connected == MFALSE) ||
+ ((pmbuf->data_len - prx_pd->rx_pkt_offset) > MV_ETH_FRAME_LEN))
+ goto upload;
+
+ if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
+ if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
+ /* Multicast pkt */
+ if ((newbuf =
+ wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MTRUE))) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
+ pmadapter->pending_bridge_pkts++;
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data, skip rxpd */
+ memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset + prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+ newbuf->data_len = pmbuf->data_len - prx_pd->rx_pkt_offset;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ }
+ }
+ } else {
+ if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
+ (wlan_get_station_entry(priv, prx_pkt->eth803_hdr.dest_addr))) {
+ /* Forwarding Intra-BSS packet */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+ pmadapter->pending_bridge_pkts++;
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ goto done;
+ } else if (MLAN_STATUS_FAILURE ==
+ wlan_check_unicast_packet(priv,
+ prx_pkt->eth803_hdr.dest_addr)) {
+ PRINTM(MDATA, "Drop Pkts: Rx dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0],
+ prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2],
+ prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4],
+ prx_pkt->eth803_hdr.dest_addr[5]);
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ }
+ upload:
+ /* Chop off RxPD */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->pparent = MNULL;
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "uAP Rx Error: moal_recv_packet returned error\n");
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ }
+
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_util.h b/drivers/net/wireless/sd8797/mlan/mlan_util.h
new file mode 100644
index 000000000000..6274f75054a0
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_util.h
@@ -0,0 +1,526 @@
+/** @file mlan_util.h
+ *
+ * @brief This file contains wrappers for linked-list,
+ * spinlock and timer defines.
+ *
+ * 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/28/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_UTIL_H_
+#define _MLAN_UTIL_H_
+
+/** Circular doubly linked list */
+typedef struct _mlan_linked_list
+{
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+} mlan_linked_list, *pmlan_linked_list;
+
+/** List head */
+typedef struct _mlan_list_head
+{
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+ /** Pointer to lock */
+ t_void *plock;
+} mlan_list_head, *pmlan_list_head;
+
+/**
+ * @brief This function initializes a list without locking
+ *
+ * @param phead List head
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_init_list(pmlan_linked_list phead)
+{
+ /* Both next and prev point to self */
+ phead->pprev = phead->pnext = (pmlan_linked_list) phead;
+}
+
+/**
+ * @brief This function initializes a list
+ *
+ * @param phead List head
+ * @param lock_required A flag for spinlock requirement
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_init_list_head(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ t_u8 lock_required,
+ mlan_status(*moal_init_lock) (t_void * handle,
+ t_void ** pplock))
+{
+ /* Both next and prev point to self */
+ util_init_list((pmlan_linked_list) phead);
+ if (lock_required)
+ moal_init_lock(pmoal_handle, &phead->plock);
+ else
+ phead->plock = 0;
+}
+
+/**
+ * @brief This function frees a list
+ *
+ * @param phead List head
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_free_list_head(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ mlan_status(*moal_free_lock) (t_void * handle,
+ t_void * plock))
+{
+ phead->pprev = phead->pnext = 0;
+ if (phead->plock)
+ moal_free_lock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function peeks into a list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_peek_list(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ mlan_status(*moal_spin_lock) (t_void * handle, t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle, t_void * plock))
+{
+ pmlan_linked_list pnode = 0;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ if (phead->pnext != (pmlan_linked_list) phead) {
+ pnode = phead->pnext;
+ }
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+ return pnode;
+}
+
+/**
+ * @brief This function queues a node at the list tail
+ *
+ * @param phead List head
+ * @param pnode List node to queue
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_enqueue_list_tail(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pold_last;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pold_last = phead->pprev;
+ pnode->pprev = pold_last;
+ pnode->pnext = (pmlan_linked_list) phead;
+
+ phead->pprev = pold_last->pnext = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function adds a node at the list head
+ *
+ * @param phead List head
+ * @param pnode List node to add
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_enqueue_list_head(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pold_first;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pold_first = phead->pnext;
+ pnode->pprev = (pmlan_linked_list) phead;
+ pnode->pnext = pold_first;
+
+ phead->pnext = pold_first->pprev = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function removes a node from the list
+ *
+ * @param phead List head
+ * @param pnode List node to remove
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_unlink_list(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * handle, t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pmy_prev;
+ pmlan_linked_list pmy_next;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pmy_prev = pnode->pprev;
+ pmy_next = pnode->pnext;
+ pmy_next->pprev = pmy_prev;
+ pmy_prev->pnext = pmy_next;
+
+ pnode->pnext = pnode->pprev = 0;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function dequeues a node from the list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_dequeue_list(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pnode;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pnode = phead->pnext;
+ if (pnode && (pnode != (pmlan_linked_list) phead)) {
+ util_unlink_list(pmoal_handle, phead, pnode, 0, 0);
+ } else {
+ pnode = 0;
+ }
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+ return pnode;
+}
+
+/** Access controlled scalar variable */
+typedef struct _mlan_scalar
+{
+ /** Value */
+ t_s32 value;
+ /** Pointer to lock */
+ t_void *plock;
+ /** Control flags */
+ t_u32 flags;
+} mlan_scalar, *pmlan_scalar;
+
+/** Flag to scalar lock acquired */
+#define MLAN_SCALAR_FLAG_UNIQUE_LOCK MBIT(16)
+
+/** scalar conditional value list */
+typedef enum _MLAN_SCALAR_CONDITIONAL
+{
+ MLAN_SCALAR_COND_EQUAL,
+ MLAN_SCALAR_COND_NOT_EQUAL,
+ MLAN_SCALAR_COND_GREATER_THAN,
+ MLAN_SCALAR_COND_GREATER_OR_EQUAL,
+ MLAN_SCALAR_COND_LESS_THAN,
+ MLAN_SCALAR_COND_LESS_OR_EQUAL
+} MLAN_SCALAR_CONDITIONAL;
+
+/**
+ * @brief This function initializes a scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param val Initial scalar value
+ * @param plock_to_use A new lock is created if NULL, else lock to use
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_init(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ t_s32 val,
+ t_void * plock_to_use,
+ mlan_status(*moal_init_lock) (t_void * handle,
+ t_void ** pplock))
+{
+ pscalar->value = val;
+ pscalar->flags = 0;
+ if (plock_to_use) {
+ pscalar->flags &= ~MLAN_SCALAR_FLAG_UNIQUE_LOCK;
+ pscalar->plock = plock_to_use;
+ } else {
+ pscalar->flags |= MLAN_SCALAR_FLAG_UNIQUE_LOCK;
+ moal_init_lock(pmoal_handle, &pscalar->plock);
+ }
+}
+
+/**
+ * @brief This function frees a scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_free(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_free_lock) (t_void * handle, t_void * plock))
+{
+ if (pscalar->flags & MLAN_SCALAR_FLAG_UNIQUE_LOCK)
+ moal_free_lock(pmoal_handle, &pscalar->plock);
+}
+
+/**
+ * @brief This function reads value from scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Stored value
+ */
+static INLINE t_s32
+util_scalar_read(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_spin_lock) (t_void * handle, t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ t_s32 val;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ val = pscalar->value;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+
+ return val;
+}
+
+/**
+ * @brief This function writes value to scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param val Value to write
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_write(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ t_s32 val,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value = val;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function increments the value in scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_increment(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value++;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function decrements the value in scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_decrement(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value--;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function adds an offset to the value in scalar,
+ * and returns the new value
+ *
+ * @param pscalar Pointer to scalar
+ * @param offset Offset value (can be negative)
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Value after offset
+ */
+static INLINE t_s32
+util_scalar_offset(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ t_s32 offset,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ t_s32 newval;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ newval = (pscalar->value += offset);
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+
+ return newval;
+}
+
+/**
+ * @brief This function writes the value to the scalar
+ * if existing value compared with other value is true.
+ *
+ * @param pscalar Pointer to scalar
+ * @param condition Condition to check
+ * @param val_compare Value to compare against current value
+ * ((A X B), where B = val_compare)
+ * @param val_to_set Value to set if comparison is true
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Comparison result (MTRUE or MFALSE)
+ */
+static INLINE t_u8
+util_scalar_conditional_write(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ MLAN_SCALAR_CONDITIONAL condition,
+ t_s32 val_compare,
+ t_s32 val_to_set,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ t_u8 update;
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+
+ switch (condition) {
+ case MLAN_SCALAR_COND_EQUAL:
+ update = (pscalar->value == val_compare);
+ break;
+ case MLAN_SCALAR_COND_NOT_EQUAL:
+ update = (pscalar->value != val_compare);
+ break;
+ case MLAN_SCALAR_COND_GREATER_THAN:
+ update = (pscalar->value > val_compare);
+ break;
+ case MLAN_SCALAR_COND_GREATER_OR_EQUAL:
+ update = (pscalar->value >= val_compare);
+ break;
+ case MLAN_SCALAR_COND_LESS_THAN:
+ update = (pscalar->value < val_compare);
+ break;
+ case MLAN_SCALAR_COND_LESS_OR_EQUAL:
+ update = (pscalar->value <= val_compare);
+ break;
+ default:
+ update = MFALSE;
+ break;
+ }
+ if (update)
+ pscalar->value = val_to_set;
+
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+ return (update) ? MTRUE : MFALSE;
+}
+
+#endif /* !_MLAN_UTIL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_wmm.c b/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
new file mode 100644
index 000000000000..4b72c9193e27
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
@@ -0,0 +1,2521 @@
+/** @file mlan_wmm.c
+ *
+ * @brief This file contains functions for WMM.
+ *
+ * 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/24/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX 512
+
+/*
+ * Upper and Lower threshold for packet queuing in the driver
+
+ * - When the number of packets queued reaches the upper limit,
+ * the driver will stop the net queue in the app/kernel space.
+
+ * - When the number of packets drops beneath the lower limit after
+ * having reached the upper limit, the driver will restart the net
+ * queue.
+ */
+
+/** Lower threshold for packet queuing in the driver.
+ * When the number of packets drops beneath the lower limit after having
+ * reached the upper limit, the driver will restart the net queue.
+ */
+#define WMM_QUEUED_PACKET_LOWER_LIMIT 180
+
+/** Upper threshold for packet queuing in the driver.
+ * When the number of packets queued reaches the upper limit, the driver
+ * will stop the net queue in the app/kernel space.
+ */
+#define WMM_QUEUED_PACKET_UPPER_LIMIT 200
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** WMM information IE */
+static const t_u8 wmm_info_ie[] = { WMM_IE, 0x07,
+ 0x00, 0x50, 0xf2, 0x02,
+ 0x00, 0x01, 0x00
+};
+
+/**
+ * AC Priorities go from AC_BK to AC_VO. The ACI enumeration for AC_BK (1)
+ * is higher than the enumeration for AC_BE (0); hence the needed
+ * mapping conversion for wmm AC to priority Queue Index
+ */
+static const t_u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_VI,
+ WMM_AC_VO
+};
+
+/**
+ * This table will be used to store the tid values based on ACs.
+ * It is initialized to default values per TID.
+ */
+t_u8 tos_to_tid[] = {
+ /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
+ 0x01, /* 0 1 0 AC_BK */
+ 0x02, /* 0 0 0 AC_BK */
+ 0x00, /* 0 0 1 AC_BE */
+ 0x03, /* 0 1 1 AC_BE */
+ 0x04, /* 1 0 0 AC_VI */
+ 0x05, /* 1 0 1 AC_VI */
+ 0x06, /* 1 1 0 AC_VO */
+ 0x07 /* 1 1 1 AC_VO */
+};
+
+/**
+ * This table inverses the tos_to_tid operation to get a priority
+ * which is in sequential order, and can be compared.
+ * Use this to compare the priority of two different TIDs.
+ */
+t_u8 tos_to_tid_inv[] = { 0x02, /* from tos_to_tid[2] = 0 */
+ 0x00, /* from tos_to_tid[0] = 1 */
+ 0x01, /* from tos_to_tid[1] = 2 */
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07
+};
+
+/**
+ * This table will provide the tid value for given ac. This table does not
+ * change and will be used to copy back the default values to tos_to_tid in
+ * case of disconnect.
+ */
+const t_u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
+
+/* Map of TOS UP values to WMM AC */
+static const mlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO
+};
+
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
+ t_u8 * ra_addr);
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef DEBUG_LEVEL2
+/**
+ * @brief Debug print function to display the priority parameters for a WMM AC
+ *
+ * @param pac_param Pointer to the AC parameters to display
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)
+{
+ const char *ac_str[] = { "BK", "BE", "VI", "VO" };
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+ ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
+ pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
+ pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
+ pac_param->ecw.ecw_max, wlan_le16_to_cpu(pac_param->tx_op_limit));
+
+ LEAVE();
+}
+
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
+#else
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param)
+#endif
+
+/**
+ * @brief Allocate route address
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ra Pointer to the route address
+ *
+ * @return ra_list
+ */
+static raListTbl *
+wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter, t_u8 * ra)
+{
+ raListTbl *ra_list = MNULL;
+
+ ENTER();
+
+ if (pmadapter->callbacks.
+ moal_malloc(pmadapter->pmoal_handle, sizeof(raListTbl), MLAN_MEM_DEF,
+ (t_u8 **) & ra_list)) {
+ PRINTM(MERROR, "Fail to allocate ra_list\n");
+ goto done;
+ }
+ util_init_list((pmlan_linked_list) ra_list);
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &ra_list->buf_head, MFALSE,
+ pmadapter->callbacks.moal_init_lock);
+
+ memcpy(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
+
+ ra_list->total_pkts = 0;
+ ra_list->tx_pause = 0;
+ PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
+ done:
+ LEAVE();
+ return ra_list;
+}
+
+/**
+ * @brief Map ACs to TID
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param queue_priority Queue_priority structure
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_queue_priorities_tid(pmlan_private priv, t_u8 queue_priority[])
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < 4; ++i) {
+ tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
+ tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
+ }
+
+ /* in case priorities have changed, force highest priority so next packet
+ will check from top to re-establish the highest */
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ HIGH_PRIO_TID,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Evaluate whether or not an AC is to be downgraded
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param eval_ac AC to evaluate for downgrading
+ *
+ * @return WMM AC The eval_ac traffic is to be sent on.
+ */
+static mlan_wmm_ac_e
+wlan_wmm_eval_downgrade_ac(pmlan_private priv, mlan_wmm_ac_e eval_ac)
+{
+ int down_ac;
+ mlan_wmm_ac_e ret_ac;
+ WmmAcStatus_t *pac_status;
+
+ ENTER();
+
+ pac_status = &priv->wmm.ac_status[eval_ac];
+
+ if (pac_status->disabled == MFALSE) {
+ LEAVE();
+ /* Okay to use this AC, its enabled */
+ return eval_ac;
+ }
+
+ /* Setup a default return value of the lowest priority */
+ ret_ac = WMM_AC_BK;
+
+ /*
+ * Find the highest AC that is enabled and does not require admission
+ * control. The spec disallows downgrading to an AC, which is enabled
+ * due to a completed admission control. Unadmitted traffic is not
+ * to be sent on an AC with admitted traffic.
+ */
+ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
+ pac_status = &priv->wmm.ac_status[down_ac];
+
+ if ((pac_status->disabled == MFALSE)
+ && (pac_status->flow_required == MFALSE))
+ /* AC is enabled and does not require admission control */
+ ret_ac = (mlan_wmm_ac_e) down_ac;
+ }
+
+ LEAVE();
+ return ret_ac;
+}
+
+/**
+ * @brief Convert the IP TOS field to an WMM AC Queue assignment
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param tos IP TOS field
+ *
+ * @return WMM AC Queue mapping of the IP TOS field
+ */
+static mlan_wmm_ac_e INLINE
+wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter, t_u32 tos)
+{
+ ENTER();
+
+ if (tos >= NELEMENTS(tos_to_ac)) {
+ LEAVE();
+ return WMM_AC_BE;
+ }
+
+ LEAVE();
+ return tos_to_ac[tos];
+}
+
+/**
+ * @brief Evaluate a given TID and downgrade it to a lower TID if the
+ * WMM Parameter IE received from the AP indicates that the AP
+ * is disabled (due to call admission control (ACM bit). Mapping
+ * of TID to AC is taken care internally
+ *
+ * @param priv Pointer to the mlan_private data struct
+ * @param tid tid to evaluate for downgrading
+ *
+ * @return Same tid as input if downgrading not required or
+ * the tid the traffic for the given tid should be downgraded to
+ */
+static t_u8 INLINE
+wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
+{
+ mlan_wmm_ac_e ac_down;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ ac_down =
+ priv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter,
+ tid)];
+ LEAVE();
+ /*
+ * Send the index to tid array, picking from the array will be
+ * taken care by dequeuing function
+ */
+ if (tid == 1 || tid == 2)
+ return ac_to_tid[ac_down][(tid + 1) % 2];
+ else if (tid >= MAX_NUM_TID)
+ return ac_to_tid[ac_down][0];
+ else
+ return ac_to_tid[ac_down][tid % 2];
+}
+
+/**
+ * @brief Delete packets in RA node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv, raListTbl * ra_list)
+{
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+ while ((pmbuf =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &ra_list->buf_head, MNULL, MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle, &ra_list->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ }
+ util_free_list_head((t_void *) pmadapter->pmoal_handle, &ra_list->buf_head,
+ pmadapter->callbacks.moal_free_lock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_wmm_del_pkts_in_ralist(pmlan_private priv, mlan_list_head * ra_list_head)
+{
+ raListTbl *ra_list;
+
+ ENTER();
+
+ ra_list =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
+ MNULL, MNULL);
+
+ while (ra_list && ra_list != (raListTbl *) ra_list_head) {
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Clean up the wmm queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_cleanup_queues(pmlan_private priv)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ wlan_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.pkts_queued[i] = 0;
+ }
+ util_scalar_write(priv->adapter->pmoal_handle, &priv->wmm.tx_pkts_queued, 0,
+ MNULL, MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all route address from RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_delete_all_ralist(pmlan_private priv)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
+ while ((ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
+ &priv->wmm.
+ tid_tbl_ptr[i].ra_list,
+ MNULL, MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) ra_list);
+ }
+
+ util_init_list((pmlan_linked_list)
+ & priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Get queue RA pointer
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list
+ */
+static raListTbl *
+wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
+{
+ raListTbl *ra_list;
+#if defined(UAP_SUPPORT)
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+#endif
+
+ ENTER();
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ if (ra_list) {
+ LEAVE();
+ return ra_list;
+ }
+#if defined(UAP_SUPPORT)
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ (0 != memcmp(priv->adapter, ra_addr, bcast_addr, sizeof(bcast_addr)))) {
+ if (MNULL == wlan_get_station_entry(priv, ra_addr)) {
+ PRINTM(MDATA, "Drop packets to unknown station\n");
+ LEAVE();
+ return MNULL;
+ }
+ }
+#endif
+ wlan_ralist_add(priv, ra_addr);
+
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ LEAVE();
+ return ra_list;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Sends wmmac host event
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param typeStr Type of host event
+ * @param srcAddr Pointer to the source Address
+ * @param tid TID
+ * @param up User priority
+ * @param status Status code or Reason code
+ *
+ * @return N/A
+ */
+static void
+wlan_send_wmmac_host_event(pmlan_private priv,
+ char *typeStr,
+ t_u8 * srcAddr, t_u8 tid, t_u8 up, t_u8 status)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent;
+ t_u8 *pOutBuf;
+
+ ENTER();
+
+ /* Format one of the following two output strings: ** -
+ TSPEC:ADDTS_RSP:[<status code>]:TID=X:UP=Y ** - TSPEC:DELTS_RX:[<reason
+ code>]:TID=X:UP=Y */
+ pevent = (mlan_event *) event_buf;
+ pOutBuf = pevent->event_buf;
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) "TSPEC:", 6);
+ pOutBuf += 6;
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) typeStr, wlan_strlen(typeStr));
+ pOutBuf += wlan_strlen(typeStr);
+
+ *pOutBuf++ = ':';
+ *pOutBuf++ = '[';
+
+ if (status >= 100) {
+ *pOutBuf++ = (status / 100) + '0';
+ status = (status % 100);
+ }
+
+ if (status >= 10) {
+ *pOutBuf++ = (status / 10) + '0';
+ status = (status % 10);
+ }
+
+ *pOutBuf++ = status + '0';
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) "]:TID", 5);
+ pOutBuf += 5;
+ *pOutBuf++ = tid + '0';
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) ":UP", 3);
+ pOutBuf += 3;
+ *pOutBuf++ = up + '0';
+
+ *pOutBuf = '\0';
+
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_REPORT_STRING;
+ pevent->event_len = wlan_strlen((const t_s8 *) (pevent->event_buf));
+
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_REPORT_STRING, pevent);
+ LEAVE();
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function gets the highest priority list pointer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param priv A pointer to mlan_private
+ * @param tid A pointer to return tid
+ *
+ * @return raListTbl
+ */
+static raListTbl *
+wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
+ pmlan_private * priv, int *tid)
+{
+ pmlan_private priv_tmp;
+ raListTbl *ptr, *head;
+ mlan_bssprio_node *bssprio_node, *bssprio_head;
+ tid_tbl_t *tid_ptr;
+ int i, j;
+ int next_prio = 0;
+ int next_tid = 0;
+ ENTER();
+
+ PRINTM(MDAT_D, "POP\n");
+ for (j = pmadapter->priv_num - 1; j >= 0; --j) {
+ if (!(util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[j].bssprio_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)))
+ continue;
+
+ if (pmadapter->bssprio_tbl[j].bssprio_cur == (mlan_bssprio_node *)
+ & pmadapter->bssprio_tbl[j].bssprio_head) {
+ pmadapter->bssprio_tbl[j].bssprio_cur =
+ pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
+ }
+
+ bssprio_head = bssprio_node = pmadapter->bssprio_tbl[j].bssprio_cur;
+
+ do {
+ priv_tmp = bssprio_node->priv;
+
+ if ((priv_tmp->port_ctrl_mode == MTRUE)
+ && (priv_tmp->port_open == MFALSE)) {
+ PRINTM(MINFO, "get_highest_prio_ptr(): "
+ "PORT_CLOSED Ignore pkts from BSS%d\n",
+ priv_tmp->bss_index);
+ /* Ignore data pkts from a BSS if port is closed */
+ goto next_intf;
+ }
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv_tmp->wmm.ra_list_spinlock);
+
+ for (i = util_scalar_read(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio,
+ MNULL, MNULL); i >= LOW_PRIO_TID; --i) {
+
+ tid_ptr = &(priv_tmp)->wmm.tid_tbl_ptr[tos_to_tid[i]];
+ if (!util_peek_list
+ (pmadapter->pmoal_handle, &tid_ptr->ra_list, MNULL, MNULL))
+ continue;
+
+ /*
+ * Always choose the next ra we transmitted
+ * last time, this way we pick the ra's in
+ * round robin fashion.
+ */
+ head = ptr = tid_ptr->ra_list_curr->pnext;
+ if (ptr == (raListTbl *) & tid_ptr->ra_list)
+ head = ptr = ptr->pnext;
+
+ do {
+ if (!ptr->tx_pause &&
+ util_peek_list(pmadapter->pmoal_handle, &ptr->buf_head,
+ MNULL, MNULL)) {
+
+ /* Because WMM only support BK/BE/VI/VO, we have 8 tid
+ We should balance the traffic of the same AC */
+ if (i % 2)
+ next_prio = i - 1;
+ else
+ next_prio = i + 1;
+ next_tid = tos_to_tid[next_prio];
+ if (priv_tmp->wmm.pkts_queued[next_tid])
+ util_scalar_write(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.
+ highest_queued_prio, next_prio,
+ MNULL, MNULL);
+ else
+ /* if highest_queued_prio > i, set it to i */
+ util_scalar_conditional_write(pmadapter->
+ pmoal_handle,
+ &priv_tmp->wmm.
+ highest_queued_prio,
+ MLAN_SCALAR_COND_GREATER_THAN,
+ i, i, MNULL, MNULL);
+ *priv = priv_tmp;
+ *tid = tos_to_tid[i];
+ /* hold priv->ra_list_spinlock to maintain ptr */
+ PRINTM(MDAT_D, "get highest prio ptr %p, tid %d\n",
+ ptr, *tid);
+ LEAVE();
+ return ptr;
+ }
+
+ if ((ptr = ptr->pnext) == (raListTbl *) & tid_ptr->ra_list)
+ ptr = ptr->pnext;
+ } while (ptr != head);
+ }
+
+ /* No packet at any TID for this priv. Mark as such to skip
+ checking TIDs for this priv (until pkt is added). */
+ util_scalar_write(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio,
+ NO_PKT_PRIO_TID, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv_tmp->wmm.
+ ra_list_spinlock);
+
+ next_intf:
+ if ((bssprio_node = bssprio_node->pnext) == (mlan_bssprio_node *)
+ & pmadapter->bssprio_tbl[j].bssprio_head)
+ bssprio_node = bssprio_node->pnext;
+ } while (bssprio_node != bssprio_head);
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function gets the number of packets in the Tx queue
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param maxBufSize Maximum buffer size
+ *
+ * @return Packet count
+ */
+static int
+wlan_num_pkts_in_txq(mlan_private * priv, raListTbl * ptr, int maxBufSize)
+{
+ int count = 0, total_size = 0;
+ pmlan_buffer pmbuf;
+
+ ENTER();
+
+ for (pmbuf = (pmlan_buffer) ptr->buf_head.pnext;
+ pmbuf != (pmlan_buffer) (&ptr->buf_head); pmbuf = pmbuf->pnext) {
+
+ total_size += pmbuf->data_len;
+ if (total_size < maxBufSize)
+ ++count;
+ else
+ break;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function sends a single packet
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptrindex ptr's TID index
+ *
+ * @return N/A
+ */
+static void INLINE
+wlan_send_single_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf;
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ MNULL, MNULL))) {
+ PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf);
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ ptr->total_pkts--;
+ pmbuf_next = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ tx_param.next_pkt_len = ((pmbuf_next)
+ ? pmbuf_next->data_len + sizeof(TxPD) : 0);
+ status = wlan_process_tx(priv, pmbuf, &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /** Queue the packet back at the head */
+ PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n", ptr, pmbuf);
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.
+ ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ priv->wmm.pkts_queued[ptrindex]++;
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ util_enqueue_list_head(pmadapter->pmoal_handle, &ptr->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ ptr->total_pkts++;
+ pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ } else {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ PRINTM(MINFO, "Nothing to send\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function checks if this mlan_buffer is already processed.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_ptr_processed(mlan_private * priv, raListTbl * ptr)
+{
+ pmlan_buffer pmbuf;
+
+ if ((pmbuf = (pmlan_buffer) util_peek_list(priv->adapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL))
+ && (pmbuf->flags & MLAN_BUF_FLAG_REQUEUED_PKT))
+ return MTRUE;
+
+ return MFALSE;
+}
+
+/**
+ * @brief This function sends a single packet that has been processed
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptrindex ptr's TID index
+ *
+ * @return N/A
+ */
+static void INLINE
+wlan_send_processed_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ MNULL, MNULL))) {
+ pmbuf_next =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ tx_param.next_pkt_len =
+ ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) : 0);
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, &tx_param);
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.
+ ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: Failed to write data\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
+ ptr->total_pkts--;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+}
+
+/**
+ * @brief This function dequeues a packet
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
+{
+ raListTbl *ptr;
+ pmlan_private priv = MNULL;
+ int ptrindex = 0;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ int tid_del = 0;
+ int tid = 0;
+
+ ENTER();
+
+ if (!(ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Note:- Spinlock is locked in wlan_wmm_get_highest_priolist_ptr when it
+ returns a pointer (for the priv it returns), and is unlocked in
+ wlan_send_processed_packet, wlan_send_single_packet or
+ wlan_11n_aggregate_pkt. The spinlock would be required for some parts
+ of both of function. But, the the bulk of these function will execute
+ w/o spinlock. Unlocking the spinlock inside these function will help
+ us avoid taking the spinlock again, check to see if the ptr is still
+ valid and then proceed. This is done purely to increase execution time.
+ */
+
+ /* Note:- Also, anybody adding code which does not get into
+ wlan_send_processed_packet, wlan_send_single_packet, or
+ wlan_11n_aggregate_pkt should make sure ra_list_spinlock is freed.
+ Otherwise there would be a lock up. */
+
+ tid = wlan_get_tid(priv->adapter, ptr);
+ if (tid >= MAX_NUM_TID)
+ tid = wlan_wmm_downgrade_tid(priv, tid);
+
+ if (wlan_is_ptr_processed(priv, ptr)) {
+ wlan_send_processed_packet(priv, ptr, ptrindex);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ if (!ptr->is_11n_enabled || wlan_is_bastream_setup(priv, ptr, tid)
+#ifdef STA_SUPPORT
+ || ((priv->sec_info.ewpa_enabled == MFALSE) &&
+ ((priv->sec_info.wpa_enabled
+ || priv->sec_info.wpa2_enabled) &&
+ priv->wpa_is_gtk_set == MFALSE))
+ || priv->wps.session_enable
+#endif /* STA_SUPPORT */
+ ) {
+ if (ptr->is_11n_enabled && wlan_is_bastream_setup(priv, ptr, tid)
+ && wlan_is_amsdu_in_ampdu_allowed(priv, ptr, tid)
+ && wlan_is_amsdu_allowed(priv, ptr, tid)
+ && (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
+ MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
+ } else
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ } else {
+ if (wlan_is_ampdu_allowed(priv, ptr, tid) &&
+ (ptr->packet_count > ptr->ba_packet_threshold)) {
+ if (wlan_is_bastream_avail(priv)) {
+ PRINTM(MINFO, "BA setup threshold %d reached. tid=%d\n",
+ ptr->packet_count, tid);
+ wlan_11n_create_txbastream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_addba(priv, tid, ptr->ra);
+ } else if (wlan_find_stream_to_delete(priv, ptr, tid, &tid_del, ra)) {
+ PRINTM(MDAT_D, "tid_del=%d tid=%d\n", tid_del, tid);
+ wlan_11n_create_txbastream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_delba(priv, tid_del, ra, 1);
+ }
+ }
+ if (wlan_is_amsdu_allowed(priv, ptr, tid) &&
+ (wlan_num_pkts_in_txq(priv, ptr,
+ pmadapter->tx_buf_size) >= MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
+ } else {
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief update tx_pause flag in ra_list
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac peer mac address
+ * @param tx_pause tx_pause flag (0/1)
+ *
+ * @return N/A
+ */
+t_void
+wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac, t_u8 tx_pause)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u32 pkt_cnt = 0;
+ t_u32 tx_pkts_queued = 0;
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
+ if (ra_list) {
+ pkt_cnt += ra_list->total_pkts;
+ ra_list->tx_pause = tx_pause;
+ }
+ }
+ if (pkt_cnt) {
+ tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ if (tx_pause)
+ tx_pkts_queued -= pkt_cnt;
+ else
+ tx_pkts_queued += pkt_cnt;
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
+ MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Get the threshold value for BA setup using system time.
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ *
+ * @return threshold value.
+ */
+t_u8
+wlan_get_random_ba_threshold(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+ t_u8 ba_threshold = 0;
+
+ ENTER();
+
+ /* setup ba_packet_threshold here random number between
+ [BA_SETUP_PACKET_OFFSET,
+ BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1] */
+
+#define BA_SETUP_MAX_PACKET_THRESHOLD 16
+#define BA_SETUP_PACKET_OFFSET 16
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+
+ ba_threshold =
+ (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD) +
+ BA_SETUP_PACKET_OFFSET;
+ PRINTM(MINFO, "setup BA after %d packets\n", ba_threshold);
+
+ LEAVE();
+ return ba_threshold;
+}
+
+/**
+ * @brief This function cleans Tx/Rx queues
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+t_void
+wlan_clean_txrx(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 i = 0;
+
+ ENTER();
+
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ wlan_cleanup_bypass_txq(pmadapter);
+ }
+
+ wlan_11n_cleanup_reorder_tbl(priv);
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ wlan_wmm_cleanup_queues(priv);
+ wlan_11n_deleteall_txbastream_tbl(priv);
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ MP_TX_AGGR_BUF_RESET(priv->adapter);
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ MP_RX_AGGR_BUF_RESET(priv->adapter);
+#endif
+ wlan_wmm_delete_all_ralist(priv);
+ memcpy(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
+ }
+#if defined(UAP_SUPPORT)
+ priv->num_drop_pkts = 0;
+#endif
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Set the WMM queue priorities to their default values
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_default_queue_priorities(pmlan_private priv)
+{
+ ENTER();
+
+ /* Default queue priorities: VO->VI->BE->BK */
+ priv->wmm.queue_priority[0] = WMM_AC_VO;
+ priv->wmm.queue_priority[1] = WMM_AC_VI;
+ priv->wmm.queue_priority[2] = WMM_AC_BE;
+ priv->wmm.queue_priority[3] = WMM_AC_BK;
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize WMM priority queues
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param pwmm_ie Pointer to the IEEEtypes_WmmParameter_t data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t * pwmm_ie)
+{
+ t_u16 cw_min, avg_back_off, tmp[4];
+ t_u32 i, j, num_ac;
+ t_u8 ac_idx;
+
+ ENTER();
+
+ if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, just set the defaults and return */
+ wlan_wmm_default_queue_priorities(priv);
+ LEAVE();
+ return;
+ }
+
+ HEXDUMP("WMM: setup_queue_priorities: param IE",
+ (t_u8 *) pwmm_ie, sizeof(IEEEtypes_WmmParameter_t));
+
+ PRINTM(MINFO, "WMM Parameter IE: version=%d, "
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
+ pwmm_ie->reserved);
+
+ for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
+ cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
+ avg_back_off
+ = (cw_min >> 1) + pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
+
+ ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac].aci_aifsn.aci];
+ priv->wmm.queue_priority[ac_idx] = ac_idx;
+ tmp[ac_idx] = avg_back_off;
+
+ PRINTM(MCMND, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
+ cw_min, avg_back_off);
+ PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
+ }
+
+ HEXDUMP("WMM: avg_back_off", (t_u8 *) tmp, sizeof(tmp));
+ HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+
+ /* Bubble sort */
+ for (i = 0; i < num_ac; i++) {
+ for (j = 1; j < num_ac - i; j++) {
+ if (tmp[j - 1] > tmp[j]) {
+ SWAP_U16(tmp[j - 1], tmp[j]);
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ } else if (tmp[j - 1] == tmp[j]) {
+ if (priv->wmm.queue_priority[j - 1]
+ < priv->wmm.queue_priority[j]) {
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ }
+ }
+ }
+ }
+
+ wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
+
+ HEXDUMP("WMM: avg_back_off, sort", (t_u8 *) tmp, sizeof(tmp));
+ DBG_HEXDUMP(MCMD_D, "WMM: queue_priority, sort", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+ LEAVE();
+}
+
+/**
+ * @brief Downgrade WMM priority queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_ac_downgrade(pmlan_private priv)
+{
+ int ac_val;
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
+
+ if (priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, default priorities */
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val] = (mlan_wmm_ac_e) ac_val;
+ }
+ } else {
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val]
+ = wlan_wmm_eval_downgrade_ac(priv, (mlan_wmm_ac_e) ac_val);
+ PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n",
+ ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Allocate and add a RA list for all TIDs with the given RA
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra Address of the receiver STA (AP in case of infra)
+ *
+ * @return N/A
+ */
+void
+wlan_ralist_add(mlan_private * priv, t_u8 * ra)
+{
+ int i;
+ raListTbl *ra_list;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
+ PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i);
+ if (!ra_list)
+ break;
+ ra_list->max_amsdu = 0;
+ if (queuing_ra_based(priv)) {
+ ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, ra);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = get_station_max_amsdu_size(priv, ra);
+ ra_list->tx_pause = wlan_is_tx_pause(priv, ra);
+ } else {
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = priv->max_amsdu;
+ }
+
+ PRINTM(MDATA, "ralist %p: is_11n_enabled=%d max_amsdu=%d\n",
+ ra_list, ra_list->is_11n_enabled, ra_list->max_amsdu);
+
+ if (ra_list->is_11n_enabled) {
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(pmadapter);
+ }
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+
+ if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the WMM state information and the WMM data path queues.
+ *
+ * @param pmadapter Pointer to the mlan_adapter data structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_init(pmlan_adapter pmadapter)
+{
+ int i, j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ if ((priv = pmadapter->priv[j])) {
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user =
+ BA_STREAM_NOT_ALLOWED;
+ else
+#endif
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ priv->wmm.pkts_queued[i] = 0;
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+
+ priv->aggr_prio_tbl[6].ampdu_ap
+ = priv->aggr_prio_tbl[6].ampdu_user = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].ampdu_ap
+ = priv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
+
+ priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ priv->add_ba_param.tx_win_size = MLAN_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_STA_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP
+#ifdef WIFI_DIRECT_SUPPORT
+ || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ ) {
+ priv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
+ priv->add_ba_param.tx_amsdu = MTRUE;
+ priv->add_ba_param.rx_amsdu = MTRUE;
+ memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+ wlan_wmm_default_queue_priorities(priv);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Setup the queue priorities and downgrade any queues as required
+ * by the WMM info. Setups default values if WMM is not active
+ * for this association.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_queues(pmlan_private priv)
+{
+ ENTER();
+ wlan_wmm_setup_queue_priorities(priv, MNULL);
+ wlan_wmm_setup_ac_downgrade(priv);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Send a command to firmware to retrieve the current WMM status
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_status_change(pmlan_private priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0, MNULL);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Check if wmm TX queue is empty
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+int
+wlan_wmm_lists_empty(pmlan_adapter pmadapter)
+{
+ int j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ if ((priv = pmadapter->priv[j])) {
+ if ((priv->port_ctrl_mode == MTRUE) && (priv->port_open == MFALSE)) {
+ PRINTM(MINFO,
+ "wmm_lists_empty: PORT_CLOSED Ignore pkts from BSS%d\n",
+ j);
+ continue;
+ }
+
+ if (util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MTRUE;
+}
+
+/**
+ * @brief Get ralist node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list or MNULL
+ */
+raListTbl *
+wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
+{
+ raListTbl *ra_list;
+ ENTER();
+ ra_list =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[tid].ra_list, MNULL,
+ MNULL);
+ while (ra_list && (ra_list != (raListTbl *)
+ & priv->wmm.tid_tbl_ptr[tid].ra_list)) {
+ if (!memcmp(priv->adapter, ra_list->ra, ra_addr, MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return ra_list;
+ }
+ ra_list = ra_list->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief Check if RA list is valid or not
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ * @param ptrindex TID pointer index
+ *
+ * @return MTRUE- valid. MFALSE- invalid.
+ */
+int
+wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int ptrindex)
+{
+ raListTbl *rlist;
+
+ ENTER();
+
+ rlist =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[ptrindex].ra_list,
+ MNULL, MNULL);
+
+ while (rlist && (rlist != (raListTbl *)
+ & priv->wmm.tid_tbl_ptr[ptrindex].ra_list)) {
+ if (rlist == ra_list) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ rlist = rlist->pnext;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief Update an existing raList with a new RA and 11n capability
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param old_ra Old receiver address
+ * @param new_ra New receiver address
+ *
+ * @return integer count of updated nodes
+ */
+int
+wlan_ralist_update(mlan_private * priv, t_u8 * old_ra, t_u8 * new_ra)
+{
+ t_u8 tid;
+ int update_count;
+ raListTbl *ra_list;
+
+ ENTER();
+
+ update_count = 0;
+
+ for (tid = 0; tid < MAX_NUM_TID; ++tid) {
+
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, old_ra);
+
+ if (ra_list) {
+ update_count++;
+
+ if (queuing_ra_based(priv))
+ ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, new_ra);
+ else
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(priv->adapter);
+ PRINTM(MINFO,
+ "ralist_update: %p, %d, %02x:%02x:%02x:%02x:%02x:%02x-->"
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", ra_list,
+ ra_list->is_11n_enabled, ra_list->ra[0], ra_list->ra[1],
+ ra_list->ra[2], ra_list->ra[3], ra_list->ra[4],
+ ra_list->ra[5], new_ra[0], new_ra[1], new_ra[2], new_ra[3],
+ new_ra[4], new_ra[5]);
+
+ memcpy(priv->adapter, ra_list->ra, new_ra, MLAN_MAC_ADDR_LENGTH);
+ }
+ }
+
+ LEAVE();
+ return update_count;
+}
+
+/**
+ * @brief Add packet to WMM queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u32 tid;
+ raListTbl *ra_list;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down;
+
+ ENTER();
+
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ if (!priv->media_connected) {
+ PRINTM(MWARN, "Drop packet in disconnect state\n");
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ tid = pmbuf->priority;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ tid_down = wlan_wmm_downgrade_tid(priv, tid);
+
+ /* In case of infra as we have already created the list during association
+ we just don't have to call get_queue_raptr, we will have only 1 raptr
+ for a tid in case of infra */
+ if (!queuing_ra_based(priv)) {
+ ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[tid_down].
+ ra_list, MNULL, MNULL);
+ } else {
+ memcpy(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
+ MLAN_MAC_ADDR_LENGTH);
+ /** put multicast/broadcast packet in the same ralist */
+ if (ra[0] & 0x01)
+ memset(pmadapter, ra, 0xff, sizeof(ra));
+ ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
+ }
+
+ if (!ra_list) {
+ PRINTM(MWARN, "Drop packet, ra_list=%p, "
+ "media_connected=%d\n", ra_list, priv->media_connected);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MDATA, "Adding pkt to ra_list %p %p priority=%d, tid_down=%d\n",
+ ra_list, pmbuf, pmbuf->priority, tid_down);
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &ra_list->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ ra_list->total_pkts++;
+ ra_list->packet_count++;
+
+ priv->wmm.pkts_queued[tid_down]++;
+ if (!ra_list->tx_pause) {
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ /* if highest_queued_prio < prio(tid_down), set it to prio(tid_down) */
+ util_scalar_conditional_write(pmadapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ MLAN_SCALAR_COND_LESS_THAN,
+ tos_to_tid_inv[tid_down],
+ tos_to_tid_inv[tid_down], MNULL, MNULL);
+ }
+ /* Record the current time the packet was queued; used to determine the
+ amount of time the packet was queued in the driver before it was sent to
+ the firmware. The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and MSDU lifetime
+ expiry. */
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->in_ts_sec,
+ &pmbuf->in_ts_usec);
+
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Process the GET_WMM_STATUS command response from firmware
+ *
+ * The GET_WMM_STATUS response may contain multiple TLVs for:
+ * - AC Queue status TLVs
+ * - Current WMM Parameter IE TLV
+ * - Admission Control action frame TLVs
+ *
+ * This function parses the TLVs and then calls further functions
+ * to process any changes in the queue prioritize or state.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ptlv Pointer to the tlv block returned in the response.
+ * @param resp_len Length of TLV block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_get_status(pmlan_private priv, t_u8 * ptlv, int resp_len)
+{
+ t_u8 *pcurrent = ptlv;
+ t_u32 tlv_len;
+ t_u8 sendWmmEvent;
+ MrvlIEtypes_Data_t *pTlvHdr;
+ MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
+ IEEEtypes_WmmParameter_t *pWmmParamIe = MNULL;
+ WmmAcStatus_t *pac_status;
+
+ MrvlIETypes_ActionFrame_t *pTlvAction;
+ IEEEtypes_Action_WMM_AddTsRsp_t *pAddTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t *pDelTs;
+
+ ENTER();
+
+ sendWmmEvent = MFALSE;
+
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", resp_len);
+ HEXDUMP("CMD_RESP: WMM_GET_STATUS", pcurrent, resp_len);
+
+ while (resp_len >= sizeof(pTlvHdr->header)) {
+ pTlvHdr = (MrvlIEtypes_Data_t *) pcurrent;
+ tlv_len = wlan_le16_to_cpu(pTlvHdr->header.len);
+
+ switch (wlan_le16_to_cpu(pTlvHdr->header.type)) {
+ case TLV_TYPE_WMMQSTATUS:
+ pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
+ PRINTM(MEVENT, "WMM_STATUS: QSTATUS TLV: %d\n",
+ pTlvWmmQStatus->queue_index);
+
+ PRINTM(MINFO,
+ "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
+ pTlvWmmQStatus->queue_index,
+ pTlvWmmQStatus->flow_required, pTlvWmmQStatus->disabled);
+
+ pac_status = &priv->wmm.ac_status[pTlvWmmQStatus->queue_index];
+ pac_status->disabled = pTlvWmmQStatus->disabled;
+ pac_status->flow_required = pTlvWmmQStatus->flow_required;
+ pac_status->flow_created = pTlvWmmQStatus->flow_created;
+ break;
+
+ case WMM_IE:
+ /*
+ * Point the regular IEEE IE 2 bytes into the Marvell IE
+ * and setup the IEEE IE type and length byte fields
+ */
+
+ PRINTM(MEVENT, "WMM STATUS: WMM IE\n");
+
+ HEXDUMP("WMM: WMM TLV:", (t_u8 *) pTlvHdr, tlv_len + 4);
+
+ pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pcurrent + 2);
+ pWmmParamIe->vend_hdr.len = (t_u8) tlv_len;
+ pWmmParamIe->vend_hdr.element_id = WMM_IE;
+
+ PRINTM(MINFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
+ pWmmParamIe->qos_info.para_set_count);
+
+ memcpy(priv->adapter,
+ (t_u8 *) & priv->curr_bss_params.bss_descriptor.wmm_ie,
+ pWmmParamIe, MIN(sizeof(IEEEtypes_WmmParameter_t),
+ (pWmmParamIe->vend_hdr.len + 2)));
+ sendWmmEvent = MTRUE;
+ break;
+
+ case TLV_TYPE_IEEE_ACTION_FRAME:
+ PRINTM(MEVENT, "WMM_STATUS: IEEE Action Frame\n");
+ pTlvAction = (MrvlIETypes_ActionFrame_t *) pcurrent;
+
+ if (pTlvAction->actionFrame.wmmAc.tspecAct.category
+ == IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC) {
+
+ switch (pTlvAction->actionFrame.wmmAc.tspecAct.action) {
+ case TSPEC_ACTION_CODE_ADDTS_RSP:
+ pAddTsRsp = &pTlvAction->actionFrame.wmmAc.addTsRsp;
+ wlan_send_wmmac_host_event(priv, "ADDTS_RSP",
+ pTlvAction->srcAddr,
+ pAddTsRsp->tspecIE.TspecBody.
+ TSInfo.TID,
+ pAddTsRsp->tspecIE.TspecBody.
+ TSInfo.UserPri,
+ pAddTsRsp->statusCode);
+ break;
+
+ case TSPEC_ACTION_CODE_DELTS:
+ pDelTs = &pTlvAction->actionFrame.wmmAc.delTs;
+ wlan_send_wmmac_host_event(priv, "DELTS_RX",
+ pTlvAction->srcAddr,
+ pDelTs->tspecIE.TspecBody.TSInfo.
+ TID,
+ pDelTs->tspecIE.TspecBody.TSInfo.
+ UserPri, pDelTs->reasonCode);
+ break;
+
+ case TSPEC_ACTION_CODE_ADDTS_REQ:
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pcurrent += (tlv_len + sizeof(pTlvHdr->header));
+ resp_len -= (tlv_len + sizeof(pTlvHdr->header));
+ }
+
+ wlan_wmm_setup_queue_priorities(priv, pWmmParamIe);
+ wlan_wmm_setup_ac_downgrade(priv);
+
+ if (sendWmmEvent) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE, MNULL);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Call back from the command module to allow insertion of a WMM TLV
+ *
+ * If the BSS we are associating to supports WMM, add the required WMM
+ * Information IE to the association request command buffer in the form
+ * of a Marvell extended IEEE IE.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ppAssocBuf Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended WMM TLV
+ * @param pWmmIE Pointer to the WMM IE for the BSS we are joining
+ * @param pHTCap Pointer to the HT IE for the BSS we are joining
+ *
+ * @return Length of data appended to the association tlv buffer
+ */
+t_u32
+wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 ** ppAssocBuf,
+ IEEEtypes_WmmParameter_t * pWmmIE,
+ IEEEtypes_HTCap_t * pHTCap)
+{
+ MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
+ t_u32 ret_len = 0;
+
+ ENTER();
+
+ /* Null checks */
+ if (!ppAssocBuf) {
+ LEAVE();
+ return 0;
+ }
+ if (!(*ppAssocBuf)) {
+ LEAVE();
+ return 0;
+ }
+
+ if (!pWmmIE) {
+ LEAVE();
+ return 0;
+ }
+
+ PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n",
+ pWmmIE->vend_hdr.element_id);
+
+ if ((priv->wmm_required
+ || (pHTCap && (pHTCap->ieee_hdr.element_id == HT_CAPABILITY)
+ && (priv->config_bands & BAND_GN || priv->config_bands & BAND_AN))
+ )
+ && pWmmIE->vend_hdr.element_id == WMM_IE) {
+ pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
+ pwmm_tlv->header.type = (t_u16) wmm_info_ie[0];
+ pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
+ pwmm_tlv->header.len = (t_u16) wmm_info_ie[1];
+ memcpy(priv->adapter, pwmm_tlv->wmm_ie, &wmm_info_ie[2],
+ pwmm_tlv->header.len);
+ if (pWmmIE->qos_info.qos_uapsd)
+ memcpy(priv->adapter,
+ (t_u8 *) (pwmm_tlv->wmm_ie + pwmm_tlv->header.len -
+ sizeof(priv->wmm_qosinfo)), &priv->wmm_qosinfo,
+ sizeof(priv->wmm_qosinfo));
+
+ ret_len = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
+ pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
+
+ HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *) pwmm_tlv, ret_len);
+ *ppAssocBuf += ret_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Compute the time delay in the driver queues for a given packet.
+ *
+ * When the packet is received at the OS/Driver interface, the current
+ * time is set in the packet structure. The difference between the present
+ * time and that received time is computed in this function and limited
+ * based on pre-compiled limits in the driver.
+ *
+ * @param priv Ptr to the mlan_private driver data struct
+ * @param pmbuf Ptr to the mlan_buffer which has been previously timestamped
+ *
+ * @return Time delay of the packet in 2ms units after having limit applied
+ */
+t_u8
+wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf)
+{
+ t_u8 ret_val = 0;
+ t_u32 out_ts_sec, out_ts_usec, queue_delay;
+
+ ENTER();
+
+ priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
+ &out_ts_sec, &out_ts_usec);
+
+ queue_delay = (out_ts_sec - pmbuf->in_ts_sec) * 1000;
+ queue_delay += (out_ts_usec - pmbuf->in_ts_usec) / 1000;
+
+ /*
+ * Queue delay is passed as a uint8 in units of 2ms (ms shifted
+ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+ *
+ * Pass max value if queue_delay is beyond the uint8 range
+ */
+ ret_val = (t_u8) (MIN(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
+
+ PRINTM(MINFO, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
+ queue_delay, ret_val);
+
+ LEAVE();
+ return ret_val;
+}
+
+/**
+ * @brief Transmit the highest priority packet awaiting in the WMM Queues
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_process_tx(pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ do {
+ if (wlan_dequeue_tx_packet(pmadapter))
+ break;
+ /* Check if busy */
+ } while (!pmadapter->data_sent && !pmadapter->tx_lock_flag
+ && !wlan_wmm_lists_empty(pmadapter));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief select wmm queue
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param tid TID 0-7
+ *
+ * @return wmm_queue priority (0-3)
+ */
+t_u8
+wlan_wmm_select_queue(mlan_private * pmpriv, t_u8 tid)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u8 i;
+ mlan_wmm_ac_e ac_down =
+ pmpriv->wmm.
+ ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter, tid)];
+
+ ENTER();
+
+ for (i = 0; i < 4; i++) {
+ if (pmpriv->wmm.queue_priority[i] == ac_down) {
+ LEAVE();
+ return i;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief Delete tx packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ * @param tid tid
+ *
+ * @return N/A
+ */
+static INLINE t_u8
+wlan_del_tx_pkts_in_ralist(pmlan_private priv,
+ mlan_list_head * ra_list_head, int tid)
+{
+ raListTbl *ra_list = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 ret = MFALSE;
+ ENTER();
+ ra_list =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
+ MNULL, MNULL);
+ while (ra_list && ra_list != (raListTbl *) ra_list_head) {
+ if (ra_list->total_pkts && (ra_list->tx_pause ||
+ (ra_list->total_pkts > RX_LOW_THRESHOLD))) {
+ if ((pmbuf =
+ (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &ra_list->buf_head, MNULL,
+ MNULL))) {
+ PRINTM(MDATA,
+ "Drop pkts: tid=%d tx_pause=%d pkts=%d brd_pkts=%d %02x:%02x:%02x:%02x:%02x:%02x\n",
+ tid, ra_list->tx_pause, ra_list->total_pkts,
+ pmadapter->pending_bridge_pkts, ra_list->ra[0],
+ ra_list->ra[1], ra_list->ra[2], ra_list->ra[3],
+ ra_list->ra[4], ra_list->ra[5]);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ priv->wmm.pkts_queued[tid]--;
+ priv->num_drop_pkts++;
+ ra_list->total_pkts--;
+ if (!ra_list->tx_pause)
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ ret = MTRUE;
+ break;
+ }
+ }
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Drop tx pkts
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_drop_tx_pkts(pmlan_private priv)
+{
+ int j;
+ static int i = 0;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (j = 0; j < MAX_NUM_TID; j++, i++) {
+ if (i == MAX_NUM_TID)
+ i = 0;
+ if (wlan_del_tx_pkts_in_ralist
+ (priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i)) {
+ i++;
+ break;
+ }
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ return;
+}
+
+/**
+ * @brief Remove peer ralist
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac peer mac address
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 * mac)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u32 pkt_cnt = 0;
+ t_u32 tx_pkts_queued = 0;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
+ if (ra_list) {
+ PRINTM(MINFO, "delete sta ralist %p\n", ra_list);
+ if (!ra_list->tx_pause)
+ pkt_cnt += ra_list->total_pkts;
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) ra_list);
+ if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr =
+ (raListTbl *) & priv->wmm.tid_tbl_ptr[i].ra_list;
+ }
+ }
+ if (pkt_cnt) {
+ tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ tx_pkts_queued -= pkt_cnt;
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
+ MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+}
+#endif
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief This function prepares the command of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_addts *paddts = (mlan_ds_wmm_addts *) pdata_buf;
+ HostCmd_DS_WMM_ADDTS_REQ *pcmd_addts = &cmd->params.add_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_addts->dialog_token)
+ + sizeof(pcmd_addts->timeout_ms)
+ + sizeof(pcmd_addts->command_result)
+ + sizeof(pcmd_addts->ieee_status_code)
+ + paddts->ie_data_len + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_addts->timeout_ms = wlan_cpu_to_le32(paddts->timeout);
+ pcmd_addts->dialog_token = paddts->dialog_tok;
+ memcpy(pmpriv->adapter,
+ pcmd_addts->tspec_data,
+ paddts->ie_data, MIN(WMM_TSPEC_SIZE, paddts->ie_data_len));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ADDTS
+ *
+ * @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_wmm_addts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_addts *paddts = MNULL;
+ const HostCmd_DS_WMM_ADDTS_REQ *presp_addts = &resp->params.add_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ paddts = (mlan_ds_wmm_addts *) & pwmm->param.addts;
+ paddts->result = presp_addts->command_result;
+ paddts->dialog_tok = presp_addts->dialog_token;
+ paddts->status_code = (t_u32) presp_addts->ieee_status_code;
+
+ if (presp_addts->command_result == MLAN_CMD_RESULT_SUCCESS) {
+ /* The tspecData field is potentially variable in size due to extra
+ IEs that may have been in the ADDTS response action frame.
+ Calculate the data length from the firmware command response. */
+ paddts->ie_data_len
+ = (t_u8) (resp->size - sizeof(presp_addts->command_result)
+ - sizeof(presp_addts->timeout_ms)
+ - sizeof(presp_addts->dialog_token)
+ - sizeof(presp_addts->ieee_status_code)
+ - S_DS_GEN);
+
+ /* Copy the TSPEC data include any extra IEs after the TSPEC */
+ memcpy(pmpriv->adapter,
+ paddts->ie_data,
+ presp_addts->tspec_data, paddts->ie_data_len);
+ } else {
+ paddts->ie_data_len = 0;
+ }
+ PRINTM(MINFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
+ paddts->result, paddts->status_code, paddts->ie_data_len);
+
+ HEXDUMP("TSPEC: ADDTS data", paddts->ie_data, paddts->ie_data_len);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_delts *pdelts = (mlan_ds_wmm_delts *) pdata_buf;
+ HostCmd_DS_WMM_DELTS_REQ *pcmd_delts = &cmd->params.del_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_delts->dialog_token)
+ + sizeof(pcmd_delts->command_result)
+ + sizeof(pcmd_delts->ieee_reason_code)
+ + pdelts->ie_data_len + S_DS_GEN);
+ cmd->result = 0;
+ pcmd_delts->ieee_reason_code = (t_u8) pdelts->status_code;
+ memcpy(pmpriv->adapter,
+ pcmd_delts->tspec_data,
+ pdelts->ie_data, MIN(WMM_TSPEC_SIZE, pdelts->ie_data_len));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of DELTS
+ *
+ * @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_wmm_delts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm;
+ IEEEtypes_WMM_TSPEC_t *pTspecIE;
+ const HostCmd_DS_WMM_DELTS_REQ *presp_delts = &resp->params.del_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pwmm->param.delts.result = presp_delts->command_result;
+
+ PRINTM(MINFO, "TSPEC: DELTS result = %d\n",
+ presp_delts->command_result);
+
+ if (presp_delts->command_result == 0) {
+ pTspecIE = (IEEEtypes_WMM_TSPEC_t *) presp_delts->tspec_data;
+ wlan_send_wmmac_host_event(pmpriv,
+ "DELTS_TX",
+ MNULL,
+ pTspecIE->TspecBody.TSInfo.TID,
+ pTspecIE->TspecBody.TSInfo.UserPri,
+ presp_delts->ieee_reason_code);
+
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_queue_config *pqcfg = (mlan_ds_wmm_queue_config *) pdata_buf;
+ HostCmd_DS_WMM_QUEUE_CONFIG *pcmd_qcfg = &cmd->params.queue_config;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_qcfg->action)
+ + sizeof(pcmd_qcfg->access_category)
+ + sizeof(pcmd_qcfg->msdu_lifetime_expiry)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qcfg->action = pqcfg->action;
+ pcmd_qcfg->access_category = pqcfg->access_category;
+ pcmd_qcfg->msdu_lifetime_expiry =
+ wlan_cpu_to_le16(pqcfg->msdu_lifetime_expiry);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_CONFIG
+ *
+ * @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_wmm_queue_config(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ const HostCmd_DS_WMM_QUEUE_CONFIG *presp_qcfg = &resp->params.queue_config;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pwmm->param.q_cfg.action = presp_qcfg->action;
+ pwmm->param.q_cfg.access_category = presp_qcfg->access_category;
+ pwmm->param.q_cfg.msdu_lifetime_expiry =
+ wlan_le16_to_cpu(presp_qcfg->msdu_lifetime_expiry);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_queue_stats *pqstats = (mlan_ds_wmm_queue_stats *) pdata_buf;
+ HostCmd_DS_WMM_QUEUE_STATS *pcmd_qstats = &cmd->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qstats->action = pqstats->action;
+ pcmd_qstats->select_is_userpri = 1;
+ pcmd_qstats->select_bin = pqstats->user_priority;
+ pcmd_qstats->pkt_count = wlan_cpu_to_le16(pqstats->pkt_count);
+ pcmd_qstats->pkt_loss = wlan_cpu_to_le16(pqstats->pkt_loss);
+ pcmd_qstats->avg_queue_delay = wlan_cpu_to_le32(pqstats->avg_queue_delay);
+ pcmd_qstats->avg_tx_delay = wlan_cpu_to_le32(pqstats->avg_tx_delay);
+ pcmd_qstats->used_time = wlan_cpu_to_le16(pqstats->used_time);
+ pcmd_qstats->policed_time = wlan_cpu_to_le16(pqstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pcmd_qstats->delay_histogram[id] =
+ wlan_cpu_to_le16(pqstats->delay_histogram[id]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_STATS
+ *
+ * @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_wmm_queue_stats(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_queue_stats *pqstats = MNULL;
+ const HostCmd_DS_WMM_QUEUE_STATS *presp_qstats = &resp->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
+
+ pqstats->action = presp_qstats->action;
+ pqstats->user_priority = presp_qstats->select_bin;
+ pqstats->pkt_count = wlan_le16_to_cpu(presp_qstats->pkt_count);
+ pqstats->pkt_loss = wlan_le16_to_cpu(presp_qstats->pkt_loss);
+ pqstats->avg_queue_delay
+ = wlan_le32_to_cpu(presp_qstats->avg_queue_delay);
+ pqstats->avg_tx_delay = wlan_le32_to_cpu(presp_qstats->avg_tx_delay);
+ pqstats->used_time = wlan_le16_to_cpu(presp_qstats->used_time);
+ pqstats->policed_time = wlan_le16_to_cpu(presp_qstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pqstats->delay_histogram[id]
+ = wlan_le16_to_cpu(presp_qstats->delay_histogram[id]);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_ts_status *pts_status = (mlan_ds_wmm_ts_status *) pdata_buf;
+ HostCmd_DS_WMM_TS_STATUS *pcmd_ts_status = &cmd->params.ts_status;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ memcpy(pmpriv->adapter, (t_void *) pcmd_ts_status, (t_void *) pts_status,
+ sizeof(HostCmd_DS_WMM_TS_STATUS));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_TS_STATUS
+ *
+ * @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_wmm_ts_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ HostCmd_DS_WMM_TS_STATUS *presp_ts_status = &resp->params.ts_status;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ presp_ts_status->medium_time
+ = wlan_le16_to_cpu(presp_ts_status->medium_time);
+ memcpy(pmpriv->adapter,
+ (t_void *) & pwmm->param.ts_status,
+ (t_void *) presp_ts_status, sizeof(mlan_ds_wmm_ts_status));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_wmm.h b/drivers/net/wireless/sd8797/mlan/mlan_wmm.h
new file mode 100644
index 000000000000..155f99330a05
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_wmm.h
@@ -0,0 +1,182 @@
+/** @file mlan_wmm.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of wmm functionalities
+ *
+ * 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/24/2008: initial version
+****************************************************/
+
+#ifndef _MLAN_WMM_H_
+#define _MLAN_WMM_H_
+
+/**
+ * @brief This function gets the TID
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ptr A pointer to RA list table
+ *
+ * @return TID
+ */
+static INLINE int
+wlan_get_tid(pmlan_adapter pmadapter, raListTbl * ptr)
+{
+ pmlan_buffer mbuf;
+
+ ENTER();
+ mbuf =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &ptr->buf_head,
+ MNULL, MNULL);
+ LEAVE();
+
+ return mbuf->priority;
+}
+
+/**
+ * @brief This function gets the length of a list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param head A pointer to mlan_list_head
+ *
+ * @return Length of list
+ */
+static INLINE int
+wlan_wmm_list_len(pmlan_adapter pmadapter, pmlan_list_head head)
+{
+ pmlan_linked_list pos;
+ int count = 0;
+
+ ENTER();
+
+ pos = head->pnext;
+
+ while (pos != (pmlan_linked_list) head) {
+ ++count;
+ pos = pos->pnext;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/** Add buffer to WMM Tx queue */
+void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Add to RA list */
+void wlan_ralist_add(mlan_private * priv, t_u8 * ra);
+/** Update the RA list */
+int wlan_ralist_update(mlan_private * priv, t_u8 * old_ra, t_u8 * new_ra);
+
+/** WMM status change command handler */
+mlan_status wlan_cmd_wmm_status_change(pmlan_private priv);
+/** Check if WMM lists are empty */
+int wlan_wmm_lists_empty(pmlan_adapter pmadapter);
+/** Process WMM transmission */
+t_void wlan_wmm_process_tx(pmlan_adapter pmadapter);
+/** Test to see if the ralist ptr is valid */
+int wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int tid);
+
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
+ t_u8 * ra_addr);
+t_u8 wlan_get_random_ba_threshold(pmlan_adapter pmadapter);
+
+/** Compute driver packet delay */
+t_u8 wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf);
+/** Initialize WMM */
+t_void wlan_wmm_init(pmlan_adapter pmadapter);
+/** Setup WMM queues */
+extern void wlan_wmm_setup_queues(pmlan_private priv);
+/* Setup default queues */
+void wlan_wmm_default_queue_priorities(pmlan_private priv);
+
+#ifdef STA_SUPPORT
+/** Process WMM association request */
+extern t_u32 wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 ** ppAssocBuf,
+ IEEEtypes_WmmParameter_t * pWmmIE,
+ IEEEtypes_HTCap_t * pHTCap);
+#endif /* STA_SUPPORT */
+
+/** setup wmm queue priorities */
+void wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t * wmm_ie);
+
+/** Downgrade WMM priority queue */
+void wlan_wmm_setup_ac_downgrade(pmlan_private priv);
+/** select WMM queue */
+t_u8 wlan_wmm_select_queue(mlan_private * pmpriv, t_u8 tid);
+#ifdef UAP_SUPPORT
+t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 * mac);
+#endif
+
+#ifdef STA_SUPPORT
+/*
+ * Functions used in the cmd handling routine
+ */
+/** WMM ADDTS request command handler */
+extern mlan_status wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM DELTS request command handler */
+extern mlan_status wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM QUEUE_CONFIG command handler */
+extern mlan_status wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM QUEUE_STATS command handler */
+extern mlan_status wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM TS_STATUS command handler */
+extern mlan_status wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/*
+ * Functions used in the cmdresp handling routine
+ */
+/** WMM get status command response handler */
+extern mlan_status wlan_ret_wmm_get_status(IN pmlan_private priv,
+ IN t_u8 * ptlv, IN int resp_len);
+/** WMM ADDTS request command response handler */
+extern mlan_status wlan_ret_wmm_addts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM DELTS request command response handler */
+extern mlan_status wlan_ret_wmm_delts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM QUEUE_CONFIG command response handler */
+extern mlan_status wlan_ret_wmm_queue_config(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM QUEUE_STATS command response handler */
+extern mlan_status wlan_ret_wmm_queue_stats(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM TS_STATUS command response handler */
+extern mlan_status wlan_ret_wmm_ts_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+#endif /* STA_SUPPORT */
+
+#endif /* !_MLAN_WMM_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan.h b/drivers/net/wireless/sd8797/mlinux/mlan.h
new file mode 100644
index 000000000000..a341e1547099
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/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/mlinux/mlan_decl.h b/drivers/net/wireless/sd8797/mlinux/mlan_decl.h
new file mode 100644
index 000000000000..41cf2bf5f2f1
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan_decl.h
@@ -0,0 +1,893 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ * 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/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "311"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef char t_s8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8;
+/** Signed short (2-bytes) */
+typedef short t_s16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16;
+/** Signed long (4-bytes) */
+typedef int t_s32;
+/** Unsigned long (4-bytes) */
+typedef unsigned int t_u32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64;
+/** Void pointer (4-bytes) */
+typedef void t_void;
+/** Size type */
+typedef t_u32 t_size;
+/** Boolean type */
+typedef t_u8 t_bool;
+
+#ifdef MLAN_64BIT
+/** Pointer type (64-bit) */
+typedef t_u64 t_ptr;
+/** Signed value (64-bit) */
+typedef t_s64 t_sval;
+#else
+/** Pointer type (32-bit) */
+typedef t_u32 t_ptr;
+/** Signed value (32-bit) */
+typedef t_s32 t_sval;
+#endif
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__ ((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifndef INLINE
+#ifdef __GNUC__
+/** inline directive */
+#define INLINE inline
+#else
+/** inline directive */
+#define INLINE __inline
+#endif
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1))
+
+/** Return the byte offset of a field in the given structure */
+#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr)&(((type *)0)->field))
+/** Return aligned offset */
+#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p)
+
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (16)
+
+/** NET IP alignment */
+#define MLAN_NET_IP_ALIGN 0
+
+/** DMA alignment */
+#define DMA_ALIGNMENT 64
+/** max size of TxPD */
+#define MAX_TXPD_SIZE 32
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT+MAX_TXPD_SIZE)
+
+/** rx data header length */
+#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN
+
+/** This is current limit on Maximum Tx AMPDU allowed */
+#define MLAN_MAX_TX_BASTREAM_SUPPORTED 2
+/** This is current limit on Maximum Rx AMPDU allowed */
+#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+
+#ifdef STA_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_STA_AMPDU_DEF_TXWINSIZE 16
+/** Default Win size attached during ADDBA response */
+#define MLAN_STA_AMPDU_DEF_RXWINSIZE 32
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 32
+/** Default Win size attached during ADDBA response */
+#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 16
+#endif /* UAP_SUPPORT */
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+/** Maximum Tx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff
+/** Maximum Rx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 12
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 19
+/** Rate index for MCS 9 */
+#define MLAN_RATE_INDEX_MCS9 21
+/** Rate index for MCS15 */
+#define MLAN_RATE_INDEX_MCS15 27
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 44
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 139
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+
+/** Size of rx data buffer */
+#define MLAN_RX_DATA_BUF_SIZE (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE (2 * 1024)
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE (4 * 1024)
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+
+/** Max retry number of IO write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+/** Buffer flag for transmit buf from moal */
+#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1)
+/** Buffer flag for malloc mlan_buffer */
+#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2)
+
+/** Buffer flag for bridge packet */
+#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+#define MIOCTL MBIT(7)
+
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MEVT_D MBIT(18)
+#define MFW_D MBIT(19)
+#define MIF_D MBIT(20)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** Memory allocation type: DMA */
+#define MLAN_MEM_DMA MBIT(0)
+
+/** Default memory allocation flag */
+#define MLAN_MEM_DEF 0
+
+/** mlan_status */
+typedef enum _mlan_status
+{
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code
+{
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware/device errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY,
+ MLAN_ERROR_FW_CMDRESP,
+ MLAN_ERROR_DATA_TX_FAIL,
+ MLAN_ERROR_DATA_RX_FAIL,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT,
+ MLAN_ERROR_PKT_INVALID,
+ MLAN_ERROR_CMD_INVALID,
+ MLAN_ERROR_CMD_TIMEOUT,
+ MLAN_ERROR_CMD_DNLD_FAIL,
+ MLAN_ERROR_CMD_CANCEL,
+ MLAN_ERROR_CMD_RESP_FAIL,
+ MLAN_ERROR_CMD_ASSOC_FAIL,
+ MLAN_ERROR_CMD_SCAN_FAIL,
+ MLAN_ERROR_IOCTL_INVALID,
+ MLAN_ERROR_IOCTL_FAIL,
+ MLAN_ERROR_EVENT_UNKNOWN,
+ MLAN_ERROR_INVALID_PARAMETER,
+ MLAN_ERROR_NO_MEM,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type
+{
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+ MLAN_BUF_TYPE_RAW_DATA,
+} mlan_buf_type;
+
+/** MLAN BSS type */
+typedef enum _mlan_bss_type
+{
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP = 1,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_BSS_TYPE_WIFIDIRECT = 2,
+#endif
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** MLAN BSS role */
+typedef enum _mlan_bss_role
+{
+ MLAN_BSS_ROLE_STA = 0,
+ MLAN_BSS_ROLE_UAP = 1,
+ MLAN_BSS_ROLE_ANY = 0xff,
+} mlan_bss_role;
+
+/** BSS role bit mask */
+#define BSS_ROLE_BIT_MASK MBIT(0)
+
+/** Get BSS role */
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type
+{
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id
+{
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
+ MLAN_EVENT_ID_FW_DISCONNECTED,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH,
+ MLAN_EVENT_ID_FW_MAX_FAIL,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH,
+ MLAN_EVENT_ID_FW_LINK_QUALITY,
+ MLAN_EVENT_ID_FW_PORT_RELEASE,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
+ MLAN_EVENT_ID_FW_HS_WAKEUP,
+ MLAN_EVENT_ID_FW_BG_SCAN,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR,
+ MLAN_EVENT_ID_FW_STOP_TX,
+ MLAN_EVENT_ID_FW_START_TX,
+ MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY,
+ MLAN_EVENT_ID_FW_BW_CHANGED,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED,
+#endif
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_UAP_FW_BSS_START,
+ MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE,
+ MLAN_EVENT_ID_UAP_FW_BSS_IDLE,
+ MLAN_EVENT_ID_UAP_FW_STA_CONNECT,
+ MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT,
+#endif
+
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED,
+ MLAN_EVENT_ID_DRV_MGMT_FRAME,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM,
+ MLAN_EVENT_ID_DRV_PASSTHRU,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT,
+ MLAN_EVENT_ID_DRV_MEAS_REPORT,
+ MLAN_EVENT_ID_DRV_REPORT_STRING,
+ MLAN_EVENT_ID_DRV_DBG_DUMP,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image
+{
+ /** Helper image buffer pointer */
+ t_u8 *phelper_buf;
+ /** Helper image length */
+ t_u32 helper_len;
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** Custom data structure */
+typedef struct _mlan_init_param
+{
+ /** Cal data buffer pointer */
+ t_u8 *pcal_data_buf;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Other custom data */
+} mlan_init_param, *pmlan_init_param;
+
+/** mlan_event data structure */
+typedef struct _mlan_event
+{
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[1];
+} mlan_event, *pmlan_event;
+
+/** mlan_event_scan_result data structure */
+typedef MLAN_PACK_START struct _mlan_event_scan_result
+{
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** More event available or not */
+ t_u8 more_event;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** Size of the response buffer */
+ t_u16 buf_size;
+ /** Number of BSS in scan response */
+ t_u8 num_of_set;
+} MLAN_PACK_END mlan_event_scan_result, *pmlan_event_scan_result;
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req
+{
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_ptr reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer
+{
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+} mlan_buffer, *pmlan_buffer;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr
+{
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+ /** BSS number */
+ t_u32 bss_num;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e
+{
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e
+{
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e
+{
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e
+{
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t,
+/** Type definition of mlan_ds_wmm_ts_status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie
+{
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+/** Max IE index to FW */
+#define MAX_MGMT_IE_INDEX_TO_FW 4
+/** Max IE index per BSS */
+#define MAX_MGMT_IE_INDEX 16
+
+/** custom IE info */
+typedef MLAN_PACK_START struct _custom_ie_info
+{
+ /** size of buffer */
+ t_u16 buf_size;
+ /** no of buffers of buf_size */
+ t_u16 buf_count;
+} MLAN_PACK_END custom_ie_info;
+
+/** TLV buffer : Max Mgmt IE */
+typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** No of tuples */
+ t_u16 count;
+ /** custom IE info tuples */
+ custom_ie_info info[MAX_MGMT_IE_INDEX];
+} MLAN_PACK_END tlvbuf_max_mgmt_ie;
+
+/** TLV buffer : custom IE */
+typedef MLAN_PACK_START struct _tlvbuf_custom_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** IE data */
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW];
+ /** Max mgmt IE TLV */
+ tlvbuf_max_mgmt_ie max_mgmt_ie;
+} MLAN_PACK_END mlan_ds_misc_custom_ie;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks
+{
+ /** moal_get_fw_data */
+ mlan_status(*moal_get_fw_data) (IN t_void * pmoal_handle,
+ IN t_u32 offset,
+ IN t_u32 len, OUT t_u8 * pbuf);
+ /** moal_init_fw_complete */
+ mlan_status(*moal_init_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status(*moal_shutdown_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status(*moal_send_packet_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+ /** moal_recv_complete */
+ mlan_status(*moal_recv_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN mlan_status status);
+ /** moal_recv_packet */
+ mlan_status(*moal_recv_packet) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status(*moal_recv_event) (IN t_void * pmoal_handle,
+ IN pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status(*moal_ioctl_complete) (IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+ /** moal_alloc_mlan_buffer */
+ mlan_status(*moal_alloc_mlan_buffer) (IN t_void * pmoal_handle,
+ IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status(*moal_free_mlan_buffer) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_write_reg */
+ mlan_status(*moal_write_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+ /** moal_read_reg */
+ mlan_status(*moal_read_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+ /** moal_write_data_sync */
+ mlan_status(*moal_write_data_sync) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status(*moal_read_data_sync) (IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_malloc */
+ mlan_status(*moal_malloc) (IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf);
+ /** moal_mfree */
+ mlan_status(*moal_mfree) (IN t_void * pmoal_handle, IN t_u8 * pbuf);
+ /** moal_memset */
+ t_void *(*moal_memset) (IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memmove */
+ t_void *(*moal_memmove) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memcmp */
+ t_s32(*moal_memcmp) (IN t_void * pmoal_handle,
+ IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+ /** moal_udelay */
+ t_void(*moal_udelay) (IN t_void * pmoal_handle, IN t_u32 udelay);
+ /** moal_get_system_time */
+ mlan_status(*moal_get_system_time) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec, OUT t_u32 * pusec);
+ /** moal_init_timer*/
+ mlan_status(*moal_init_timer) (IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+ /** moal_free_timer */
+ mlan_status(*moal_free_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_start_timer*/
+ mlan_status(*moal_start_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status(*moal_stop_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_init_lock */
+ mlan_status(*moal_init_lock) (IN t_void * pmoal_handle,
+ OUT t_void ** pplock);
+ /** moal_free_lock */
+ mlan_status(*moal_free_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_lock */
+ mlan_status(*moal_spin_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_unlock */
+ mlan_status(*moal_spin_unlock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_print */
+ t_void(*moal_print) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...);
+ /** moal_print_netintf */
+ t_void(*moal_print_netintf) (IN t_void * pmoal_handle,
+ IN t_u32 bss_index, IN t_u32 level);
+ /** moal_assert */
+ t_void(*moal_assert) (IN t_void * pmoal_handle, IN t_u32 cond);
+} mlan_callbacks, *pmlan_callbacks;
+
+/** Interrupt Mode SDIO */
+#define INT_MODE_SDIO 0
+/** Interrupt Mode GPIO */
+#define INT_MODE_GPIO 1
+
+/** Parameter unchanged, use MLAN default setting */
+#define MLAN_INIT_PARA_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define MLAN_INIT_PARA_ENABLED 1
+/** Parameter disabled, override MLAN default setting */
+#define MLAN_INIT_PARA_DISABLED 2
+
+/** mlan_device data structure */
+typedef struct _mlan_device
+{
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+#if defined(STA_SUPPORT)
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+#endif
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(IN pmlan_device pmdevice,
+ OUT t_void ** ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(IN t_void * pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter,
+ IN pmlan_fw_image pmfw);
+
+/** Custom data pass API */
+MLAN_API mlan_status mlan_set_init_param(IN t_void * pmlan_adapter,
+ IN pmlan_init_param pparam);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(IN t_void * pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(IN t_void * pmlan_adapter);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf);
+
+/** Packet Reception complete callback */
+MLAN_API mlan_status mlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+
+/** interrupt handler */
+MLAN_API t_void mlan_interrupt(IN t_void * pmlan_adapter);
+
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(IN t_void * pmlan_adapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** mlan select wmm queue */
+MLAN_API t_u8 mlan_select_wmm_queue(IN t_void * pmlan_adapter,
+ IN t_u8 bss_num, IN t_u8 tid);
+#endif /* !_MLAN_DECL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h b/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h
new file mode 100644
index 000000000000..2431e06f48fa
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h
@@ -0,0 +1,1322 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ * 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/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** FIX IES size in beacon buffer */
+#define WLAN_802_11_FIXED_IE_SIZE 12
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension*/
+#define WLAN_SUPPORTED_RATES_EXT 32
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound */
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0xF000) >> 12)
+#else
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0x00F0) >> 4)
+#endif
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+
+#ifdef STA_SUPPORT
+ COUNTRY_INFO = 7,
+#endif /* STA_SUPPORT */
+
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ SUPPORTED_CHANNELS = 36,
+ CHANNEL_SWITCH_ANN = 37,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+
+ WPA_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t
+{
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+}
+MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+}
+MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | \
+ MBIT(12) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ t_u8 rsrvd1:2;
+ t_u8 dsss_ofdm:1;
+ t_u8 rsvrd2:2;
+ t_u8 short_slot_time:1;
+ t_u8 rsrvd3:1;
+ t_u8 spectrum_mgmt:1;
+ t_u8 chan_agility:1;
+ t_u8 pbcc:1;
+ t_u8 short_preamble:1;
+ t_u8 privacy:1;
+ t_u8 cf_poll_rqst:1;
+ t_u8 cf_pollable:1;
+ t_u8 ibss:1;
+ t_u8 ess:1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t
+{
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value in milliseconds */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t
+{
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t
+{
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time in milliseconds */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t
+{
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t
+{
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t
+{
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** cipher TKIP */
+#define WPA_CIPHER_TKIP 2
+/** cipher AES */
+#define WPA_CIPHER_AES_CCM 4
+/** AKM: 8021x */
+#define RSN_AKM_8021X 1
+/** AKM: PSK */
+#define RSN_AKM_PSK 2
+
+/** wpa_suite_t */
+typedef MLAN_PACK_START struct _wpa_suite_t
+{
+ /** OUI */
+ t_u8 oui[3];
+ /** tyep */
+ t_u8 type;
+} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t;
+
+/** wpa_suite_ucast_t */
+typedef MLAN_PACK_START struct
+{
+ /* count */
+ t_u16 count;
+ /** wpa_suite list */
+ wpa_suite list[1];
+} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+
+/** IEEEtypes_Rsn_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t
+{
+ /** Rsn : Element ID */
+ t_u8 element_id;
+ /** Rsn : Length */
+ t_u8 len;
+ /** Rsn : version */
+ t_u16 version;
+ /** Rsn : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Rsn : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t;
+
+/** IEEEtypes_Wpa_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t
+{
+ /** Wpa : Element ID */
+ t_u8 element_id;
+ /** Wpa : Length */
+ t_u8 len;
+ /** Wpa : oui */
+ t_u8 oui[4];
+ /** version */
+ t_u16 version;
+ /** Wpa : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Wpa : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t;
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t
+{
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t
+{
+
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t
+{
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Enumerator for TSPEC direction */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e
+{
+
+ TSPEC_DIR_UPLINK = 0,
+ TSPEC_DIR_DOWNLINK = 1,
+ /* 2 is a reserved value */
+ TSPEC_DIR_BIDIRECT = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e;
+
+/** Enumerator for TSPEC PSB */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e
+{
+
+ TSPEC_PSB_LEGACY = 0,
+ TSPEC_PSB_TRIG = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e;
+
+/** Enumerator for TSPEC Ack Policy */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e
+{
+
+ TSPEC_ACKPOLICY_NORMAL = 0,
+ TSPEC_ACKPOLICY_NOACK = 1,
+ /* 2 is reserved */
+ TSPEC_ACKPOLICY_BLOCKACK = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e;
+
+/** Enumerator for TSPEC Trafffice type */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e
+{
+
+ TSPEC_TRAFFIC_APERIODIC = 0,
+ TSPEC_TRAFFIC_PERIODIC = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e;
+
+/** Data structure of WMM TSPEC information */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 Reserved17_23:7; // ! Reserved
+ t_u8 Schedule:1;
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 Aggregation:1; // ! Reserved
+ t_u8 AccessPolicy2:1; // !
+ t_u8 AccessPolicy1:1; // !
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+#else
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 AccessPolicy1:1; // !
+ t_u8 AccessPolicy2:1; // !
+ t_u8 Aggregation:1; // ! Reserved
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 Schedule:1;
+ t_u8 Reserved17_23:7; // ! Reserved
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t;
+
+/** Data structure of WMM TSPEC Nominal Size */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+ t_u16 Size:15; // ! Nominal size in octets
+#else
+ t_u16 Size:15; // ! Nominal size in octets
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t;
+
+/** Data structure of WMM TSPEC SBWA */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Whole:3; // ! Whole portion
+ t_u16 Fractional:13; // ! Fractional portion
+#else
+ t_u16 Fractional:13; // ! Fractional portion
+ t_u16 Whole:3; // ! Whole portion
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA;
+
+/** Data structure of WMM TSPEC Body */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo;
+ IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize;
+ t_u16 MaximumMSDUSize;
+ t_u32 MinServiceInterval;
+ t_u32 MaxServiceInterval;
+ t_u32 InactivityInterval;
+ t_u32 SuspensionInterval;
+ t_u32 ServiceStartTime;
+ t_u32 MinimumDataRate;
+ t_u32 MeanDataRate;
+ t_u32 PeakDataRate;
+ t_u32 MaxBurstSize;
+ t_u32 DelayBound;
+ t_u32 MinPHYRate;
+ IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance;
+ t_u16 MediumTime;
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t;
+
+/** Data structure of WMM TSPEC all elements */
+typedef MLAN_PACK_START struct
+{
+ t_u8 ElementId;
+ t_u8 Len;
+ t_u8 OuiType[4]; /* 00:50:f2:02 */
+ t_u8 OuiSubType; /* 01 */
+ t_u8 Version;
+
+ IEEEtypes_WMM_TSPEC_Body_t TspecBody;
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t;
+
+/** WMM Action Category values */
+typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e
+{
+
+ IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0,
+ IEEE_MGMT_ACTION_CATEGORY_QOS = 1,
+ IEEE_MGMT_ACTION_CATEGORY_DLS = 2,
+ IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3,
+ IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4,
+ IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5,
+ IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6,
+ IEEE_MGMT_ACTION_CATEGORY_HT = 7,
+
+ IEEE_MGMT_ACTION_CATEGORY_WNM = 10,
+ IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11,
+
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17
+} MLAN_PACK_END IEEEtypes_ActionCategory_e;
+
+/** WMM TSPEC operations */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e
+{
+
+ TSPEC_ACTION_CODE_ADDTS_REQ = 0,
+ TSPEC_ACTION_CODE_ADDTS_RSP = 1,
+ TSPEC_ACTION_CODE_DELTS = 2,
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e;
+
+/** WMM TSPEC Category Action Base */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_ActionCategory_e category;
+ IEEEtypes_WMM_Tspec_Action_e action;
+ t_u8 dialogToken;
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t;
+
+/** WMM TSPEC AddTS request structure */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t;
+
+/** WMM TSPEC AddTS response structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t;
+
+/** WMM TSPEC DelTS structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 reasonCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t;
+
+/** union of WMM TSPEC structures */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+
+ IEEEtypes_Action_WMM_AddTsReq_t addTsReq;
+ IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t delTs;
+
+} MLAN_PACK_END IEEEtypes_Action_WMMAC_t;
+
+/** union of WMM TSPEC & Action category */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_ActionCategory_e category;
+
+ IEEEtypes_Action_WMMAC_t wmmAc;
+
+} MLAN_PACK_END IEEEtypes_ActionFrame_t;
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+#ifdef STA_SUPPORT
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+#endif /* STA_SUPPORT */
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t
+{
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t
+{
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t
+{
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t
+{
+ /** Extended Capabilities value */
+ t_u8 ext_cap_value;
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t
+{
+ /** OBSS Scan Passive Dwell in milliseconds */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell in milliseconds */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval in seconds */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/* IEEE Channel Switch Announcement Element (7.3.2.20) */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a chan switch element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 37 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */
+ t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */
+ t_u8 chan_switch_count; /**< # of TBTTs before channel switch */
+
+} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+#else
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct
+{
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch Announcement IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+#ifdef STA_SUPPORT
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Scan all the channels in specified band */
+#define BAND_SPECIFIED 0x80
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid
+{
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan
+{
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 1, Passive = 2 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief Reserved
+ */
+ t_u8 reserved;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/** Default scan interval in millisecond*/
+#define DEFAULT_BGSCAN_INTERVAL 30000
+
+/** action get all, except pps/uapsd config */
+#define BG_SCAN_ACT_GET 0x0000
+/** action set all, except pps/uapsd config */
+#define BG_SCAN_ACT_SET 0x0001
+/** action get pps/uapsd config */
+#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100
+/** action set pps/uapsd config */
+#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101
+/** action set all */
+#define BG_SCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define BG_SCAN_SSID_MATCH 0x0001
+/** ssid match and RSSI exceeded */
+#define BG_SCAN_SSID_RSSI_MATCH 0x0004
+/** Maximum number of channels that can be sent in bg scan config */
+#define WLAN_BG_SCAN_CHAN_MAX 32
+
+/**
+ * Input structure to configure bs scan cmd to firmware
+ */
+typedef MLAN_PACK_START struct
+{
+ /** action */
+ t_u16 action;
+ /** enable/disable */
+ t_u8 enable;
+ /** BSS type:
+ * MLAN_SCAN_MODE_BSS (infrastructure)
+ * MLAN_SCAN_MODE_IBSS (adhoc)
+ * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_type;
+ /** number of channel scanned during each scan */
+ t_u8 chan_per_scan;
+ /** interval between consecutive scan */
+ t_u32 scan_interval;
+ /** bit 0: ssid match bit 1: ssid match and SNR exceeded
+ * bit 2: ssid match and RSSI exceeded
+ * bit 31: wait for all channel scan to complete to report scan result
+ */
+ t_u32 report_condition;
+ /* Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+ /** RSSI threshold */
+ t_u8 rssi_threshold;
+ /** SNR threshold */
+ t_u8 snr_threshold;
+ /** repeat count */
+ t_u16 repeat_count;
+ /** SSID filter list used in the to limit the scan results */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_bgscan_cfg;
+#endif /* STA_SUPPORT */
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t
+{
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** Indicate disabling 11n when associate with AP */
+ t_u8 disable_11n;
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+#ifdef STA_SUPPORT
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+#endif /* STA_SUPPORT */
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+#ifdef STA_SUPPORT
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+#endif
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h b/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h
new file mode 100644
index 000000000000..964de9197ffe
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h
@@ -0,0 +1,2981 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ * 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/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** Enumeration for IOCTL request ID */
+enum _mlan_ioctl_req_id
+{
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL,
+ MLAN_OID_SCAN_SPECIFIC_SSID,
+ MLAN_OID_SCAN_USER_CONFIG,
+ MLAN_OID_SCAN_CONFIG,
+ MLAN_OID_SCAN_GET_CURRENT_BSS,
+ MLAN_OID_SCAN_CANCEL,
+ MLAN_OID_SCAN_TABLE_FLUSH,
+ MLAN_OID_SCAN_BGSCAN_CONFIG,
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START,
+ MLAN_OID_BSS_STOP,
+ MLAN_OID_BSS_MODE,
+ MLAN_OID_BSS_CHANNEL,
+ MLAN_OID_BSS_CHANNEL_LIST,
+ MLAN_OID_BSS_MAC_ADDR,
+ MLAN_OID_BSS_MULTICAST_LIST,
+ MLAN_OID_BSS_FIND_BSS,
+ MLAN_OID_IBSS_BCN_INTERVAL,
+ MLAN_OID_IBSS_ATIM_WINDOW,
+ MLAN_OID_IBSS_CHANNEL,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_BSS_CONFIG,
+ MLAN_OID_UAP_DEAUTH_STA,
+ MLAN_OID_UAP_BSS_RESET,
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ MLAN_OID_BSS_ROLE,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_WIFI_DIRECT_MODE,
+#endif
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL,
+ MLAN_OID_BAND_CFG,
+ MLAN_OID_ANT_CFG,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_REMAIN_CHAN_CFG,
+#endif
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT,
+#if defined(UAP_SUPPORT)
+ MLAN_OID_SNMP_MIB_DOT11D,
+ MLAN_OID_SNMP_MIB_DOT11H,
+#endif
+ MLAN_OID_SNMP_MIB_DTIM_PERIOD,
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS,
+ MLAN_OID_GET_SIGNAL,
+ MLAN_OID_GET_FW_INFO,
+ MLAN_OID_GET_VER_EXT,
+ MLAN_OID_GET_BSS_INFO,
+ MLAN_OID_GET_DEBUG_INFO,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_STA_LIST,
+#endif
+
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE,
+ MLAN_OID_SEC_CFG_WPA_ENABLED,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY,
+ MLAN_OID_SEC_CFG_PASSPHRASE,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED,
+ MLAN_OID_SEC_CFG_ESUPP_MODE,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED,
+ MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG,
+ MLAN_OID_GET_DATA_RATE,
+ MLAN_OID_SUPPORTED_RATES,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG,
+ MLAN_OID_POWER_CFG_EXT,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS,
+ MLAN_OID_PM_CFG_HS_CFG,
+ MLAN_OID_PM_CFG_INACTIVITY_TO,
+ MLAN_OID_PM_CFG_DEEP_SLEEP,
+ MLAN_OID_PM_CFG_SLEEP_PD,
+ MLAN_OID_PM_CFG_PS_CFG,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS,
+#ifdef UAP_SUPPORT
+ MLAN_OID_PM_CFG_PS_MODE,
+#endif /* UAP_SUPPORT */
+ MLAN_OID_PM_INFO,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE,
+ MLAN_OID_WMM_CFG_QOS,
+ MLAN_OID_WMM_CFG_ADDTS,
+ MLAN_OID_WMM_CFG_DELTS,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG,
+ MLAN_OID_WMM_CFG_QUEUE_STATS,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS,
+ MLAN_OID_WMM_CFG_TS_STATUS,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX,
+ MLAN_OID_11N_HTCAP_CFG,
+ MLAN_OID_11N_CFG_ADDBA_REJECT,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL,
+ MLAN_OID_11N_CFG_ADDBA_PARAM,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL,
+ MLAN_OID_11N_CFG_SUPPORTED_MCS_SET,
+ MLAN_OID_11N_CFG_TX_BF_CAP,
+ MLAN_OID_11N_CFG_TX_BF_CFG,
+ MLAN_OID_11N_CFG_STREAM_CFG,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+#ifdef STA_SUPPORT
+ MLAN_OID_11D_CFG_ENABLE,
+ MLAN_OID_11D_CLR_CHAN_TABLE,
+#endif /* STA_SUPPORT */
+ MLAN_OID_11D_DOMAIN_INFO,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW,
+ MLAN_OID_EEPROM_RD,
+ MLAN_OID_MEM_RW,
+
+ /* Multi-Radio Configuration Group */
+ MLAN_IOCTL_MFR_CFG = 0x00100000,
+
+ /* 802.11h Configuration Group */
+ MLAN_IOCTL_11H_CFG = 0x00110000,
+ MLAN_OID_11H_CHANNEL_CHECK,
+ MLAN_OID_11H_LOCAL_POWER_CONSTRAINT,
+#if defined(DFS_TESTING_SUPPORT)
+ MLAN_OID_11H_DFS_TESTING,
+#endif
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE,
+ MLAN_OID_MISC_REGION,
+ MLAN_OID_MISC_WARM_RESET,
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ MLAN_OID_MISC_SDIO_MPA_CTRL,
+#endif
+ MLAN_OID_MISC_HOST_CMD,
+ MLAN_OID_MISC_SYS_CLOCK,
+ MLAN_OID_MISC_SOFT_RESET,
+ MLAN_OID_MISC_WWS,
+ MLAN_OID_MISC_INIT_SHUTDOWN,
+ MLAN_OID_MISC_CUSTOM_IE,
+ MLAN_OID_MISC_TX_DATAPAUSE,
+ MLAN_OID_MISC_IP_ADDR,
+ MLAN_OID_MISC_MAC_CONTROL,
+ MLAN_OID_MISC_MEF_CFG,
+ MLAN_OID_MISC_CFP_CODE,
+ MLAN_OID_MISC_COUNTRY_CODE,
+ MLAN_OID_MISC_THERMAL,
+ MLAN_OID_MISC_RX_MGMT_IND,
+ MLAN_OID_MISC_SUBSCRIBE_EVENT,
+#ifdef DEBUG_LEVEL1
+ MLAN_OID_MISC_DRVDBG,
+#endif
+ MLAN_OID_MISC_OTP_USER_DATA,
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum _mlan_act_ioctl
+{
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL
+};
+
+/** Enumeration for generic enable/disable */
+enum _mlan_act_generic
+{
+ MLAN_ACT_DISABLE = 0,
+ MLAN_ACT_ENABLE = 1
+};
+
+/** Enumeration for scan mode */
+enum _mlan_scan_mode
+{
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum _mlan_scan_type
+{
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE
+};
+
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 4
+
+/** Default number of probes to send on each channel */
+#define DEFAULT_PROBES 4
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value in microseconds from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid
+{
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows after the fixed_field_length
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /*
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ /* t_u8 bss_info_buffer[0]; */
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params
+{
+ /** Scan channel time for specific scan in milliseconds */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan in milliseconds */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan in milliseconds */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan
+{
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req
+{
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp
+{
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+ /* Age in seconds */
+ t_u32 age_in_secs;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg
+{
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Extended Scan */
+ t_u32 ext_scan;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union
+ {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum _mlan_bss_mode
+{
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+
+/** max Wmm AC queues */
+#define MAX_AC_QUEUES 4
+
+/** Maximum atim window in milliseconds */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list
+{
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Max channel */
+#define MLAN_MAX_CHANNEL 165
+
+/** Maximum number of channels in table */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq
+{
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list
+{
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/** mlan_ssid_bssid data structure for MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS */
+typedef struct _mlan_ssid_bssid
+{
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+ /** index in BSSID list, start from 1 */
+ t_u32 idx;
+} mlan_ssid_bssid;
+
+#ifdef UAP_SUPPORT
+/** Maximum packet forward control value */
+#define MAX_PKT_FWD_CTRL 15
+/** Maximum BEACON period */
+#define MAX_BEACON_PERIOD 4000
+/** Minimum BEACON period */
+#define MIN_BEACON_PERIOD 50
+/** Maximum DTIM period */
+#define MAX_DTIM_PERIOD 100
+/** Minimum DTIM period */
+#define MIN_DTIM_PERIOD 1
+/** Maximum TX Power Limit */
+#define MAX_TX_POWER 20
+/** Minimum TX Power Limit */
+#define MIN_TX_POWER 0
+/** MAX station count */
+#define MAX_STA_COUNT 10
+/** Maximum RTS threshold */
+#define MAX_RTS_THRESHOLD 2347
+/** Maximum fragmentation threshold */
+#define MAX_FRAG_THRESHOLD 2346
+/** Minimum fragmentation threshold */
+#define MIN_FRAG_THRESHOLD 256
+/** data rate 54 M */
+#define DATA_RATE_54M 108
+/** antenna A */
+#define ANTENNA_MODE_A 0
+/** antenna B */
+#define ANTENNA_MODE_B 1
+/** transmit antenna */
+#define TX_ANTENNA 1
+/** receive antenna */
+#define RX_ANTENNA 0
+/** Maximum stage out time */
+#define MAX_STAGE_OUT_TIME 864000
+/** Minimum stage out time */
+#define MIN_STAGE_OUT_TIME 300
+/** Maximum Retry Limit */
+#define MAX_RETRY_LIMIT 14
+
+/** Maximum group key timer in seconds */
+#define MAX_GRP_TIMER 86400
+
+/** Maximum value of 4 byte configuration */
+#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */
+
+/** Band config ACS mode */
+#define BAND_CONFIG_ACS_MODE 0x40
+/** Band config manual */
+#define BAND_CONFIG_MANUAL 0x00
+
+/** Maximum data rates */
+#define MAX_DATA_RATES 14
+
+/** auto data rate */
+#define DATA_RATE_AUTO 0
+
+/**filter mode: disable */
+#define MAC_FILTER_MODE_DISABLE 0
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_ALLOW_MAC 1
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_BLOCK_MAC 2
+/** Maximum mac filter num */
+#define MAX_MAC_FILTER_NUM 16
+
+/* Bitmap for protocol to use */
+/** No security */
+#define PROTOCOL_NO_SECURITY 0x01
+/** Static WEP */
+#define PROTOCOL_STATIC_WEP 0x02
+/** WPA */
+#define PROTOCOL_WPA 0x08
+/** WPA2 */
+#define PROTOCOL_WPA2 0x20
+/** WP2 Mixed */
+#define PROTOCOL_WPA2_MIXED 0x28
+/** EAP */
+#define PROTOCOL_EAP 0x40
+/** WAPI */
+#define PROTOCOL_WAPI 0x80
+
+/** Key_mgmt_psk */
+#define KEY_MGMT_NONE 0x04
+/** Key_mgmt_none */
+#define KEY_MGMT_PSK 0x02
+/** Key_mgmt_eap */
+#define KEY_MGMT_EAP 0x01
+
+/** TKIP */
+#define CIPHER_TKIP 0x04
+/** AES CCMP */
+#define CIPHER_AES_CCMP 0x08
+
+/** Valid cipher bitmap */
+#define VALID_CIPHER_BITMAP 0x0c
+
+/** Channel List Entry */
+typedef struct _channel_list
+{
+ /** Channel Number */
+ t_u8 chan_number;
+ /** Band Config */
+ t_u8 band_config_type;
+} scan_chan_list;
+
+/** mac_filter data structure */
+typedef struct _mac_filter
+{
+ /** mac filter mode */
+ t_u16 filter_mode;
+ /** mac adress count */
+ t_u16 mac_count;
+ /** mac address list */
+ mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM];
+} mac_filter;
+
+/** wpa parameter */
+typedef struct _wpa_param
+{
+ /** Pairwise cipher WPA */
+ t_u8 pairwise_cipher_wpa;
+ /** Pairwise cipher WPA2 */
+ t_u8 pairwise_cipher_wpa2;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** RSN replay protection */
+ t_u8 rsn_protection;
+ /** passphrase length */
+ t_u32 length;
+ /** passphrase */
+ t_u8 passphrase[64];
+ /**group key rekey time in seconds */
+ t_u32 gk_rekey_time;
+} wpa_param;
+
+/** wep key */
+typedef struct _wep_key
+{
+ /** key index 0-3 */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** length */
+ t_u16 length;
+ /** key data */
+ t_u8 key[26];
+} wep_key;
+
+/** wep param */
+typedef struct _wep_param
+{
+ /** key 0 */
+ wep_key key0;
+ /** key 1 */
+ wep_key key1;
+ /** key 2 */
+ wep_key key2;
+ /** key 3 */
+ wep_key key3;
+} wep_param;
+
+/** Data structure of WMM QoS information */
+typedef struct _wmm_qos_info_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_qos_info_t, *pwmm_qos_info_t;
+
+/** Data structure of WMM ECW */
+typedef struct _wmm_ecw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_ecw_t, *pwmm_ecw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _wmm_aci_aifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _wmm_ac_parameters_t
+{
+ wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */
+ wmm_ecw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} wmm_ac_parameters_t, *pwmm_ac_parameters_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _wmm_parameter_t
+{
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+} wmm_parameter_t, *pwmm_parameter_t;
+
+/** mlan_bss_param
+ * Note: For each entry you must enter an invalid value
+ * in the MOAL function woal_set_sys_config_invalid_data().
+ * Otherwise for a valid data an unwanted TLV will be
+ * added to that command.
+ */
+typedef struct _mlan_uap_bss_param
+{
+ /** AP mac addr */
+ mlan_802_11_mac_addr mac_addr;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Broadcast ssid control */
+ t_u8 bcast_ssid_ctl;
+ /** Radio control: on/off */
+ t_u8 radio_ctl;
+ /** dtim period */
+ t_u8 dtim_period;
+ /** beacon period */
+ t_u16 beacon_period;
+ /** rates */
+ t_u8 rates[MAX_DATA_RATES];
+ /** Tx data rate */
+ t_u16 tx_data_rate;
+ /** multicast/broadcast data rate */
+ t_u16 mcbc_data_rate;
+ /** Tx power level in dBm */
+ t_u8 tx_power_level;
+ /** Tx antenna */
+ t_u8 tx_antenna;
+ /** Rx antenna */
+ t_u8 rx_antenna;
+ /** packet forward control */
+ t_u8 pkt_forward_ctl;
+ /** max station count */
+ t_u16 max_sta_count;
+ /** mac filter */
+ mac_filter filter;
+ /** station ageout timer in unit of 100ms */
+ t_u32 sta_ageout_timer;
+ /** PS station ageout timer in unit of 100ms */
+ t_u32 ps_sta_ageout_timer;
+ /** RTS threshold */
+ t_u16 rts_threshold;
+ /** fragmentation threshold */
+ t_u16 frag_threshold;
+ /** retry_limit */
+ t_u16 retry_limit;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+ /** preamble type */
+ t_u8 preamble_type;
+ /** band cfg */
+ t_u8 band_cfg;
+ /** channel */
+ t_u8 channel;
+ /** auth mode */
+ t_u16 auth_mode;
+ /** encryption protocol */
+ t_u16 protocol;
+ /** key managment type */
+ t_u16 key_mgmt;
+ /** wep param */
+ wep_param wep_cfg;
+ /** wpa param */
+ wpa_param wpa_cfg;
+ /** Mgmt IE passthru mask */
+ t_u32 mgmt_ie_passthru_mask;
+ /*
+ * 11n HT Cap HTCap_t ht_cap
+ */
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Enable 2040 Coex */
+ t_u8 enable_2040coex;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+ /** BSS status */
+ t_u16 bss_status;
+#ifdef WIFI_DIRECT_SUPPORT
+ /* pre shared key */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+#endif /* WIFI_DIRECT_SUPPORT */
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+ /** Wmm parameters */
+ wmm_parameter_t wmm_para;
+} mlan_uap_bss_param;
+
+/** mlan_deauth_param */
+typedef struct _mlan_deauth_param
+{
+ /** STA mac addr */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** deauth reason */
+ t_u16 reason_code;
+} mlan_deauth_param;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** mode: disable wifi direct */
+#define WIFI_DIRECT_MODE_DISABLE 0
+/** mode: listen */
+#define WIFI_DIRECT_MODE_LISTEN 1
+/** mode: GO */
+#define WIFI_DIRECT_MODE_GO 2
+/** mode: client */
+#define WIFI_DIRECT_MODE_CLIENT 3
+/** mode: find */
+#define WIFI_DIRECT_MODE_FIND 4
+/** mode: stop find */
+#define WIFI_DIRECT_MODE_STOP_FIND 5
+#endif
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union
+ {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+#ifdef UAP_SUPPORT
+ /** BSS param for AP mode */
+ mlan_uap_bss_param bss_config;
+ /** deauth param for MLAN_OID_UAP_DEAUTH_STA */
+ mlan_deauth_param deauth_param;
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ /** BSS role */
+ t_u8 bss_role;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ t_u16 wfd_mode;
+#endif
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for band */
+enum _mlan_band_def
+{
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+};
+
+/** NO secondary channel */
+#define NO_SEC_CHANNEL 0
+/** secondary channel is above primary channel */
+#define SEC_CHANNEL_ABOVE 1
+/** secondary channel is below primary channel */
+#define SEC_CHANNEL_BELOW 3
+/** Channel bandwidth */
+#define CHANNEL_BW_20MHZ 0
+#define CHANNEL_BW_40MHZ_ABOVE 1
+#define CHANNEL_BW_40MHZ_BELOW 3
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg
+{
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+ /** Ad-hoc channel bandwidth */
+ t_u32 sec_chan_offset;
+ /** fw supported band */
+ t_u32 fw_bands;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg
+{
+ /** Tx antenna mode */
+ t_u32 tx_antenna;
+ /** Rx antenna mode */
+ t_u32 rx_antenna;
+} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */
+typedef struct _mlan_ds_remain_chan
+{
+ /** remove flag */
+ t_u16 remove;
+ /** status */
+ t_u8 status;
+ /** Band cfg */
+ t_u8 bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} mlan_ds_remain_chan, *pmlan_ds_remain_chan;
+#endif
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union
+ {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg ant_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ t_u32 antenna;
+#ifdef WIFI_DIRECT_SUPPORT
+ /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */
+ mlan_ds_remain_chan remain_chan;
+#endif
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union
+ {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+#if defined(UAP_SUPPORT)
+ /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
+ t_u32 oid_value;
+#endif
+ /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */
+ t_u32 dtim_period;
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum _mlan_adhoc_status
+{
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED, ADHOC_STARTING
+};
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats
+{
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_uap_stats
+{
+ /** tkip mic failures */
+ t_u32 tkip_mic_failures;
+ /** ccmp decrypt errors */
+ t_u32 ccmp_decrypt_errors;
+ /** wep undecryptable count */
+ t_u32 wep_undecryptable_count;
+ /** wep icv error count */
+ t_u32 wep_icv_error_count;
+ /** decrypt failure count */
+ t_u32 decrypt_failure_count;
+ /** dot11 multicast tx count */
+ t_u32 mcast_tx_count;
+ /** dot11 failed count */
+ t_u32 failed_count;
+ /** dot11 retry count */
+ t_u32 retry_count;
+ /** dot11 multi retry count */
+ t_u32 multi_retry_count;
+ /** dot11 frame duplicate count */
+ t_u32 frame_dup_count;
+ /** dot11 rts success count */
+ t_u32 rts_success_count;
+ /** dot11 rts failure count */
+ t_u32 rts_failure_count;
+ /** dot11 ack failure count */
+ t_u32 ack_failure_count;
+ /** dot11 rx ragment count */
+ t_u32 rx_fragment_count;
+ /** dot11 mcast rx frame count */
+ t_u32 mcast_rx_frame_count;
+ /** dot11 fcs error count */
+ t_u32 fcs_error_count;
+ /** dot11 tx frame count */
+ t_u32 tx_frame_count;
+ /** dot11 rsna tkip cm invoked */
+ t_u32 rsna_tkip_cm_invoked;
+ /** dot11 rsna 4way handshake failures */
+ t_u32 rsna_4way_hshk_failures;
+} mlan_ds_uap_stats, *pmlan_ds_uap_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal
+{
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info
+{
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** fw supported band */
+ t_u8 fw_bands;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext
+{
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info
+{
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Band */
+ t_u8 bss_band;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level in dBm */
+ t_u32 max_power_level;
+ /** Min power level in dBm */
+ t_u32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+#ifdef STA_SUPPORT
+ /** Capability Info */
+ t_u16 capability_info;
+ /** Beacon Interval */
+ t_u16 beacon_interval;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Association Id */
+ t_u16 assoc_id;
+ /** AP/Peer supported rates */
+ t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES];
+#endif /* STA_SUPPORT */
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** amsdu flag */
+ t_u8 amsdu;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** amsdu flag */
+ t_u8 amsdu;
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info
+{
+ /* WMM AC_BK count */
+ t_u32 wmm_ac_bk;
+ /* WMM AC_BE count */
+ t_u32 wmm_ac_be;
+ /* WMM AC_VI count */
+ t_u32 wmm_ac_vi;
+ /* WMM AC_VO count */
+ t_u32 wmm_ac_vo;
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Corresponds to curr_tx_buf_size member of mlan_adapter*/
+ t_u32 curr_tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+#ifdef STA_SUPPORT
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+#endif /** STA_SUPPORT */
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+ /** Corresponds to pps_uapsd_mode member of mlan_adapter */
+ t_u16 pps_uapsd_mode;
+ /** Corresponds to sleep_period.period member of mlan_adapter */
+ t_u16 sleep_pd;
+ /** Corresponds to wmm_qosinfo member of mlan_private */
+ t_u8 qos_cfg;
+ /** Corresponds to tx_lock_flag member of mlan_adapter */
+ t_u8 tx_lock_flag;
+ /** Corresponds to port_open member of mlan_private */
+ t_u8 port_open;
+ /** Corresponds to scan_processing member of mlan_adapter */
+ t_u32 scan_processing;
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+ /** pendig tx pkts */
+ t_u32 tx_pkts_queued;
+#ifdef UAP_SUPPORT
+ /** pending bridge pkts */
+ t_u16 num_bridge_pkts;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+} mlan_debug_info, *pmlan_debug_info;
+
+#ifdef UAP_SUPPORT
+/** Maximum number of clients supported by AP */
+#define MAX_NUM_CLIENTS MAX_STA_COUNT
+
+/** station info */
+typedef struct _sta_info
+{
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mfg status */
+ t_u8 power_mfg_status;
+ /** RSSI */
+ t_s8 rssi;
+} sta_info;
+
+/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */
+typedef struct _mlan_ds_sta_list
+{
+ /** station count */
+ t_u16 sta_count;
+ /** station list */
+ sta_info info[MAX_NUM_CLIENTS];
+} mlan_ds_sta_list, *pmlan_ds_sta_list;
+#endif
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info
+{
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union
+ {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ mlan_debug_info debug_info;
+#ifdef UAP_SUPPORT
+ /** UAP Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_uap_stats ustats;
+ /** UAP station list for MLAN_OID_UAP_STA_LIST */
+ mlan_ds_sta_list sta_list;
+#endif
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum _mlan_auth_mode
+{
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/** Enumeration for encryption mode */
+enum _mlan_encryption_mode
+{
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+};
+
+/** Enumeration for PSK */
+enum _mlan_psk_type
+{
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+};
+
+/** The bit to indicate the key is for unicast */
+#define MLAN_KEY_INDEX_UNICAST 0x40000000
+/** The key index to indicate default key */
+#define MLAN_KEY_INDEX_DEFAULT 0x000000ff
+/** Maximum key length */
+// #define MLAN_MAX_KEY_LENGTH 32
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** PMK length */
+#define MLAN_PMK_HEXSTR_LENGTH 64
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+/** packet number size */
+#define PN_SIZE 16
+/** max seq size of wpa/wpa2 key */
+#define SEQ_MAX_SIZE 8
+
+/** key flag for tx_seq */
+#define KEY_FLAG_TX_SEQ_VALID 0x00000001
+/** key flag for rx_seq */
+#define KEY_FLAG_RX_SEQ_VALID 0x00000002
+/** key flag for group key */
+#define KEY_FLAG_GROUP_KEY 0x00000004
+/** key flag for tx and rx */
+#define KEY_FLAG_SET_TX_KEY 0x00000008
+/** key flag for remove key */
+#define KEY_FLAG_REMOVE_KEY 0x80000000
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key
+{
+ /** Key disabled, all other fields will be ignore when this flag set to MTRUE */
+ t_u32 key_disable;
+ /** key removed flag, when this flag is set to MTRUE, only key_index will be check */
+ t_u32 key_remove;
+ /** Key index, used as current tx key index when is_current_wep_key is set to MTRUE */
+ t_u32 key_index;
+ /** Current Tx key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+ /** key flags */
+ t_u32 key_flags;
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t
+{
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t
+{
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_KEY_LENGTH];
+} mlan_pmk_t;
+
+/** Embedded supplicant RSN type: No RSN */
+#define RSN_TYPE_NO_RSN MBIT(0)
+/** Embedded supplicant RSN type: WPA */
+#define RSN_TYPE_WPA MBIT(3)
+/** Embedded supplicant RSN type: WPA-NONE */
+#define RSN_TYPE_WPANONE MBIT(4)
+/** Embedded supplicant RSN type: WPA2 */
+#define RSN_TYPE_WPA2 MBIT(5)
+/** Embedded supplicant RSN type: RFU */
+#define RSN_TYPE_VALID_BITS (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2)
+
+/** Embedded supplicant cipher type: TKIP */
+#define EMBED_CIPHER_TKIP MBIT(2)
+/** Embedded supplicant cipher type: AES */
+#define EMBED_CIPHER_AES MBIT(3)
+/** Embedded supplicant cipher type: RFU */
+#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES)
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase
+{
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union
+ {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode
+{
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union
+ {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */
+ t_u32 port_ctrl_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for MLAN_OID_SEC_CFG_EWPA_ENABLED */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for rate type */
+enum _mlan_rate_type
+{
+ MLAN_RATE_INDEX,
+ MLAN_RATE_VALUE
+};
+
+/** Enumeration for rate format */
+enum _mlan_rate_format
+{
+ MLAN_RATE_FORMAT_LG = 0,
+ MLAN_RATE_FORMAT_HT,
+ MLAN_RATE_FORMAT_AUTO = 0xFF,
+};
+/** Max bitmap rates size */
+#define MAX_BITMAP_RATES_SIZE 10
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t
+{
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type. 0: index; 1: valude */
+ t_u32 rate_type;
+ /** Rate/MCS index or rate value if fixed rate */
+ t_u32 rate;
+ /** Rate Bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+} mlan_rate_cfg_t;
+
+/** HT channel bandwidth */
+typedef enum _mlan_ht_bw
+{
+ MLAN_HT_BW20,
+ MLAN_HT_BW40,
+} mlan_ht_bw;
+
+/** HT guard interval */
+typedef enum _mlan_ht_gi
+{
+ MLAN_HT_LGI,
+ MLAN_HT_SGI,
+} mlan_ht_gi;
+
+/** Band and BSS mode */
+typedef struct _mlan_band_data_rate
+{
+ /** Band configuration */
+ t_u8 config_bands;
+ /** BSS mode (Infra or IBSS) */
+ t_u8 bss_mode;
+} mlan_band_data_rate;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate
+{
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+
+ /** Tx channel bandwidth */
+ t_u32 tx_ht_bw;
+ /** Tx guard interval */
+ t_u32 tx_ht_gi;
+ /** Rx channel bandwidth */
+ t_u32 rx_ht_bw;
+ /** Rx guard interval */
+ t_u32 rx_ht_gi;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union
+ {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ /** Band/BSS mode for getting supported rates */
+ mlan_band_data_rate rate_band_cfg;
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t
+{
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level in dBm */
+ t_u32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+
+/** The HT BW40 bit in Tx rate index */
+#define TX_RATE_HT_BW40_BIT MBIT(7)
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext
+{
+ /** Length of power_data */
+ t_u32 len;
+ /** Buffer of power configuration data */
+ t_u32 power_data[MAX_POWER_TABLE_SIZE];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union
+ {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Host sleep config condition: broadcast data */
+#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0)
+/** Host sleep config condition: unicast data */
+#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1)
+/** Host sleep config condition: mac event */
+#define HOST_SLEEP_COND_MAC_EVENT MBIT(2)
+/** Host sleep config condition: multicast data */
+#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3)
+
+/** Host sleep config conditions: Default */
+#define HOST_SLEEP_DEF_COND (HOST_SLEEP_COND_BROADCAST_DATA | HOST_SLEEP_COND_UNICAST_DATA | HOST_SLEEP_COND_MAC_EVENT)
+/** Host sleep config GPIO : Default */
+#define HOST_SLEEP_DEF_GPIO 0xff
+/** Host sleep config gap : Default */
+#define HOST_SLEEP_DEF_GAP 200
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg
+{
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: broadcast data
+ * Bit1: unicast data
+ * Bit2: mac event
+ * Bit3: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u32 gpio;
+ /** Gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */
+ t_u32 gap;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time in milliseconds for auto deep sleep */
+#define DEEP_SLEEP_IDLE_TIME 100
+
+typedef struct _mlan_ds_auto_ds
+{
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time in milliseconds */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to for MLAN_OID_PM_CFG_INACTIVITY_TO */
+typedef struct _mlan_ds_inactivity_to
+{
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period in milliseconds */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period in milliseconds */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Local listen interval disable */
+#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1)
+/** Minimum listen interval */
+#define MRVDRV_MIN_LISTEN_INTERVAL 0
+
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Match listen interval to closest DTIM */
+#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd
+
+/** Minimum adhoc awake period */
+#define MIN_ADHOC_AWAKE_PD 0
+/** Maximum adhoc awake period */
+#define MAX_ADHOC_AWAKE_PD 31
+/** Special adhoc awake period */
+#define SPECIAL_ADHOC_AWAKE_PD 255
+
+/** Minimum beacon miss timeout in milliseconds */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout in milliseconds */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS in milliseconds */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS in milliseconds */
+#define MAX_DELAY_TO_PS 65535
+/** Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+/** Default delay to PS in milliseconds */
+#define DELAY_TO_PS_DEFAULT 1000
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg
+{
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Adhoc awake period */
+ t_u32 adhoc_awake_period;
+ /** Beacon miss timeout in milliseconds */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS in milliseconds */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params
+{
+ /** Error */
+ t_u32 error;
+ /** Offset in microseconds */
+ t_u32 offset;
+ /** Stable time in microseconds */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** sleep_param */
+typedef struct _ps_sleep_param
+{
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** minimum sleep period (micro second) */
+ t_u32 min_sleep;
+ /** maximum sleep period (micro second) */
+ t_u32 max_sleep;
+} ps_sleep_param;
+
+/** inactivity sleep_param */
+typedef struct _inact_sleep_param
+{
+ /** inactivity timeout (micro second) */
+ t_u32 inactivity_to;
+ /** miniumu awake period (micro second) */
+ t_u32 min_awake;
+ /** maximum awake period (micro second) */
+ t_u32 max_awake;
+} inact_sleep_param;
+
+/** flag for ps mode */
+#define PS_FLAG_PS_MODE 1
+/** flag for sleep param */
+#define PS_FLAG_SLEEP_PARAM 2
+/** flag for inactivity sleep param */
+#define PS_FLAG_INACT_SLEEP_PARAM 4
+
+/** Disable power mode */
+#define PS_MODE_DISABLE 0
+/** Enable periodic dtim ps */
+#define PS_MODE_PERIODIC_DTIM 1
+/** Enable inactivity ps */
+#define PS_MODE_INACTIVITY 2
+
+/** mlan_ds_ps_mgmt */
+typedef struct _mlan_ds_ps_mgmt
+{
+ /** flags for valid field */
+ t_u16 flags;
+ /** power mode */
+ t_u16 ps_mode;
+ /** sleep param */
+ ps_sleep_param sleep_param;
+ /** inactivity sleep param */
+ inact_sleep_param inact_param;
+} mlan_ds_ps_mgmt;
+
+/** mlan_ds_ps_info */
+typedef struct _mlan_ds_ps_info
+{
+ /** suspend allowed flag */
+ t_u32 is_suspend_allowed;
+} mlan_ds_ps_info;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union
+ {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+ mlan_ds_sleep_params sleep_params;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */
+ mlan_ds_ps_mgmt ps_mgmt;
+ /** power info for MLAN_OID_PM_INFO */
+ mlan_ds_ps_info ps_info;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */
+ + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** User Priority */
+ t_u8 user_priority;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+/** Type definition of mlan_ds_wmm_queue_stats for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+/** Type definition of mlan_ds_wmm_queue_status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts
+{
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the ADDTS + buffering for any extra IEs */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts
+{
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+typedef struct _mlan_ds_wmm_queue_config
+{
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union
+ {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum _mlan_wps_status
+{
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union
+ {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+/** Supported stream modes */
+#define HT_STREAM_MODE_1X1 0x11
+#define HT_STREAM_MODE_2X2 0x22
+
+/* Both 2.4G and 5G band selected */
+#define BAND_SELECT_BOTH 0
+/* Band 2.4G selected */
+#define BAND_SELECT_BG 1
+/* Band 5G selected */
+#define BAND_SELECT_A 2
+
+/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */
+typedef struct _mlan_ds_11n_htcap_cfg
+{
+ /** HT Capability information */
+ t_u32 htcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg;
+
+/** Type definition of mlan_ds_11n_addba_param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+typedef struct _mlan_ds_11n_addba_param
+{
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg
+{
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+ /** Band selection */
+ t_u32 misc_cfg;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** BF Global Configuration */
+#define BF_GLOBAL_CONFIGURATION 0x00
+/** Performs NDP sounding for PEER specified */
+#define TRIGGER_SOUNDING_FOR_PEER 0x01
+/** TX BF interval for channel sounding */
+#define SET_GET_BF_PERIODICITY 0x02
+/** Tell FW not to perform any sounding for peer */
+#define TX_BF_FOR_PEER_ENBL 0x03
+/** TX BF SNR threshold for peer */
+#define SET_SNR_THR_PEER 0x04
+
+/* Maximum number of peer MAC and status/SNR tuples */
+#define MAX_PEER_MAC_TUPLES 10
+
+/** Any new subcommand structure should be declare here */
+
+/** bf global cfg args */
+typedef struct _mlan_bf_global_cfg_args
+{
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval in milliseconds */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} mlan_bf_global_cfg_args;
+
+/** trigger sounding args */
+typedef struct _mlan_trigger_sound_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} mlan_trigger_sound_args;
+
+/** bf periodicity args */
+typedef struct _mlan_bf_periodicity_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval in milliseconds */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} mlan_bf_periodicity_args;
+
+/** tx bf peer args */
+typedef struct _mlan_tx_bf_peer_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} mlan_tx_bf_peer_args;
+
+/** SNR threshold args */
+typedef struct _mlan_snr_thr_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR for peer */
+ t_u8 snr;
+} mlan_snr_thr_args;
+
+/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */
+typedef struct _mlan_ds_11n_tx_bf_cfg
+{
+ /** BF Action */
+ t_u16 bf_action;
+ /** Action */
+ t_u16 action;
+ /** Number of peers */
+ t_u32 no_of_peers;
+ union
+ {
+ mlan_bf_global_cfg_args bf_global_cfg;
+ mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES];
+ mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES];
+ mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES];
+ mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES];
+ } body;
+} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl
+{
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+typedef struct _mlan_ds_11n_aggr_prio_tbl
+{
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union
+ {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ mlan_ds_11n_htcap_cfg htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_FIELD];
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Transmit Beamforming configuration */
+ mlan_ds_11n_tx_bf_cfg tx_bf;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+#ifdef STA_SUPPORT
+/** Data structure for subband set */
+typedef struct _mlan_ds_subband_set_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} mlan_ds_subband_set_t;
+
+/** Domain regulatory information */
+typedef struct _mlan_ds_11d_domain_info
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} mlan_ds_11d_domain_info;
+#endif
+
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union
+ {
+#ifdef STA_SUPPORT
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+ /** Domain info for MLAN_OID_11D_DOMAIN_INFO */
+ mlan_ds_11d_domain_info domain_info;
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ /** tlv data for MLAN_OID_11D_DOMAIN_INFO */
+ t_u8 domain_tlv[MAX_IE_SIZE];
+#endif /* UAP_SUPPORT */
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for register type */
+enum _mlan_reg_type
+{
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_CAU = 5,
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw
+{
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom
+{
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw
+{
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union
+ {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** Multi-Radio Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------*/
+/** 802.11h Configuration Group */
+/*-----------------------------------------------------------------*/
+#if defined(DFS_TESTING_SUPPORT)
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */
+typedef struct _mlan_ds_11h_dfs_testing
+{
+ /** User-configured CAC period in milliseconds, 0 to use default */
+ t_u16 usr_cac_period_msec;
+ /** User-configured NOP period in seconds, 0 to use default */
+ t_u16 usr_nop_period_sec;
+ /** User-configured skip channel change, 0 to disable */
+ t_u8 usr_no_chan_change;
+ /** User-configured fixed channel to change to, 0 to use random channel */
+ t_u8 usr_fixed_new_chan;
+} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing;
+#endif
+
+/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */
+typedef struct _mlan_ds_11h_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ union
+ {
+ /** Local power constraint for MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */
+ t_s8 usr_local_power_constraint;
+#if defined(DFS_TESTING_SUPPORT)
+ /** User-configuation for MLAN_OID_11H_DFS_TESTING */
+ mlan_ds_11h_dfs_testing dfs_testing;
+#endif
+ } param;
+} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER 2048
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum _mlan_ie_type
+{
+ MLAN_IE_TYPE_GEN_IE = 0,
+#ifdef STA_SUPPORT
+ MLAN_IE_TYPE_ARP_FILTER,
+#endif /* STA_SUPPORT */
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie
+{
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl for MLAN_OID_MISC_SDIO_MPA_CTRL */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl
+{
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd
+{
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MLAN_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock
+{
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Enumeration for function init/shutdown */
+enum _mlan_func_cmd
+{
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_tx_datapause for MLAN_OID_MISC_TX_DATAPAUSE */
+typedef struct _mlan_ds_misc_tx_datapause
+{
+ /** Tx data pause flag */
+ t_u16 tx_pause;
+ /** Max number of Tx buffers for all PS clients */
+ t_u16 tx_buf_cnt;
+} mlan_ds_misc_tx_datapause;
+
+/** IP address length */
+#define IPADDR_LEN (16)
+/** Max number of ip */
+#define MAX_IPADDR (4)
+/** IP address type - IPv4*/
+#define IPADDR_TYPE_IPV4 (1)
+/** IP operation remove */
+#define MLAN_IPADDR_OP_IP_REMOVE (0)
+/** IP operation ARP filter */
+#define MLAN_IPADDR_OP_ARP_FILTER MBIT(0)
+/** IP operation ARP response */
+#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1)
+
+/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */
+typedef struct _mlan_ds_misc_ipaddr_cfg
+{
+ /** Operation code */
+ t_u32 op_code;
+ /** IP address type */
+ t_u32 ip_addr_type;
+ /** Number of IP */
+ t_u32 ip_addr_num;
+ /** IP address */
+ t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN];
+} mlan_ds_misc_ipaddr_cfg;
+
+/* MEF configuration disable */
+#define MEF_CFG_DISABLE 0
+/* MEF configuration Rx filter enable */
+#define MEF_CFG_RX_FILTER_ENABLE 1
+/* MEF configuration auto ARP response */
+#define MEF_CFG_AUTO_ARP_RESP 2
+/* MEF configuration host command */
+#define MEF_CFG_HOSTCMD 0xFFFF
+
+/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */
+typedef struct _mlan_ds_misc_mef_cfg
+{
+ /** Sub-ID for operation */
+ t_u32 sub_id;
+ /** Parameter according to sub-ID */
+ union
+ {
+ /** MEF command buffer for MEF_CFG_HOSTCMD */
+ mlan_ds_misc_cmd cmd_buf;
+ } param;
+} mlan_ds_misc_mef_cfg;
+
+/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_misc_cfp_code
+{
+ /** CFP table code for 2.4GHz */
+ t_u32 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u32 cfp_code_a;
+} mlan_ds_misc_cfp_code;
+
+/** Type definition of mlan_ds_misc_country_code for MLAN_OID_MISC_COUNTRY_CODE */
+typedef struct _mlan_ds_misc_country_code
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+} mlan_ds_misc_country_code;
+
+/** BITMAP for subscribe event rssi low */
+#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
+/** BITMAP for subscribe event snr low */
+#define SUBSCRIBE_EVT_SNR_LOW MBIT(1)
+/** BITMAP for subscribe event max fail */
+#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2)
+/** BITMAP for subscribe event beacon missed */
+#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3)
+/** BITMAP for subscribe event rssi high */
+#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4)
+/** BITMAP for subscribe event snr high */
+#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5)
+/** BITMAP for subscribe event data rssi low */
+#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6)
+/** BITMAP for subscribe event data snr low */
+#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7)
+/** BITMAP for subscribe event data rssi high */
+#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8)
+/** BITMAP for subscribe event data snr high */
+#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9)
+/** BITMAP for subscribe event link quality */
+#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
+/** BITMAP for subscribe event pre_beacon_lost */
+#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+/** default PRE_BEACON_MISS_COUNT */
+#define DEFAULT_PRE_BEACON_MISS 30
+
+/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_subscribe_evt
+{
+ /** bitmap for subscribe event */
+ t_u16 evt_bitmap;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_snr_freq;
+ /** Failure count threshold */
+ t_u8 failure_count;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 failure_count_freq;
+ /** num of missed beacons */
+ t_u8 beacon_miss;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 beacon_miss_freq;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_snr_freq;
+ /* Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /* Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+ /* Number of pre missed beacons */
+ t_u8 pre_beacon_miss;
+} mlan_ds_subscribe_evt;
+
+/** Max OTP user data length */
+#define MAX_OTP_USER_DATA_LEN 252
+
+/** Type definition of mlan_ds_misc_otp_user_data for MLAN_OID_MISC_OTP_USER_DATA */
+typedef struct _mlan_ds_misc_otp_user_data
+{
+ /** Reserved */
+ t_u16 reserved;
+ /** OTP user data length */
+ t_u16 user_data_length;
+ /** User data buffer */
+ t_u8 user_data[MAX_OTP_USER_DATA_LEN];
+} mlan_ds_misc_otp_user_data;
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union
+ {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */
+ mlan_ds_misc_custom_ie cust_ie;
+ /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */
+ mlan_ds_misc_tx_datapause tx_datapause;
+ /** IP address configuration */
+ mlan_ds_misc_ipaddr_cfg ipaddr_cfg;
+ /** MAC control for MLAN_OID_MISC_MAC_CONTROL */
+ t_u32 mac_ctrl;
+ /** MEF configuration for MLAN_OID_MISC_MEF_CFG */
+ mlan_ds_misc_mef_cfg mef_cfg;
+ /** CFP code for MLAN_OID_MISC_CFP_CODE */
+ mlan_ds_misc_cfp_code cfp_code;
+ /** Country code for MLAN_OID_MISC_COUNTRY_CODE */
+ mlan_ds_misc_country_code country_code;
+ /** Thermal reading for MLAN_OID_MISC_THERMAL */
+ t_u32 thermal;
+ /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
+ t_u32 mgmt_subtype_mask;
+ /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */
+ mlan_ds_subscribe_evt subscribe_event;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ mlan_ds_misc_otp_user_data otp_user_data;
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
new file mode 100644
index 000000000000..6b2a01f5c218
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
@@ -0,0 +1,1687 @@
+/** @file moal_cfg80211.c
+ *
+ * @brief This file contains the functions for CFG80211.
+ *
+ * Copyright (C) 2011-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.
+ *
+ */
+
+#include "moal_cfg80211.h"
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** Supported rates to be advertised to the cfg80211 */
+static struct ieee80211_rate cfg80211_rates[] = {
+ {.bitrate = 10,.hw_value = 2,},
+ {.bitrate = 20,.hw_value = 4,},
+ {.bitrate = 55,.hw_value = 11},
+ {.bitrate = 110,.hw_value = 22,},
+ {.bitrate = 220,.hw_value = 44,},
+ {.bitrate = 60,.hw_value = 12,},
+ {.bitrate = 90,.hw_value = 18,},
+ {.bitrate = 120,.hw_value = 24,},
+ {.bitrate = 180,.hw_value = 36,},
+ {.bitrate = 240,.hw_value = 48,},
+ {.bitrate = 360,.hw_value = 72,},
+ {.bitrate = 480,.hw_value = 96,},
+ {.bitrate = 540,.hw_value = 108,},
+ {.bitrate = 720,.hw_value = 144,},
+};
+
+/** Channel definitions for 2 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel cfg80211_channels_2ghz[] = {
+ {.center_freq = 2412,.hw_value = 1,.max_power = 20},
+ {.center_freq = 2417,.hw_value = 2,.max_power = 20},
+ {.center_freq = 2422,.hw_value = 3,.max_power = 20},
+ {.center_freq = 2427,.hw_value = 4,.max_power = 20},
+ {.center_freq = 2432,.hw_value = 5,.max_power = 20},
+ {.center_freq = 2437,.hw_value = 6,.max_power = 20},
+ {.center_freq = 2442,.hw_value = 7,.max_power = 20},
+ {.center_freq = 2447,.hw_value = 8,.max_power = 20},
+ {.center_freq = 2452,.hw_value = 9,.max_power = 20},
+ {.center_freq = 2457,.hw_value = 10,.max_power = 20},
+ {.center_freq = 2462,.hw_value = 11,.max_power = 20},
+ {.center_freq = 2467,.hw_value = 12,.max_power = 20},
+ {.center_freq = 2472,.hw_value = 13,.max_power = 20},
+ {.center_freq = 2484,.hw_value = 14,.max_power = 20},
+};
+
+/** Channel definitions for 5 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel cfg80211_channels_5ghz[] = {
+ {.center_freq = 5040,.hw_value = 8,.max_power = 20},
+ {.center_freq = 5060,.hw_value = 12,.max_power = 20},
+ {.center_freq = 5080,.hw_value = 16,.max_power = 20},
+ {.center_freq = 5170,.hw_value = 34,.max_power = 20},
+ {.center_freq = 5190,.hw_value = 38,.max_power = 20},
+ {.center_freq = 5210,.hw_value = 42,.max_power = 20},
+ {.center_freq = 5230,.hw_value = 46,.max_power = 20},
+ {.center_freq = 5180,.hw_value = 36,.max_power = 20},
+ {.center_freq = 5200,.hw_value = 40,.max_power = 20},
+ {.center_freq = 5220,.hw_value = 44,.max_power = 20},
+ {.center_freq = 5240,.hw_value = 48,.max_power = 20},
+ {.center_freq = 5260,.hw_value = 52,.max_power = 20},
+ {.center_freq = 5280,.hw_value = 56,.max_power = 20},
+ {.center_freq = 5300,.hw_value = 60,.max_power = 20},
+ {.center_freq = 5320,.hw_value = 64,.max_power = 20},
+ {.center_freq = 5500,.hw_value = 100,.max_power = 20},
+ {.center_freq = 5520,.hw_value = 104,.max_power = 20},
+ {.center_freq = 5540,.hw_value = 108,.max_power = 20},
+ {.center_freq = 5560,.hw_value = 112,.max_power = 20},
+ {.center_freq = 5580,.hw_value = 116,.max_power = 20},
+ {.center_freq = 5600,.hw_value = 120,.max_power = 20},
+ {.center_freq = 5620,.hw_value = 124,.max_power = 20},
+ {.center_freq = 5640,.hw_value = 128,.max_power = 20},
+ {.center_freq = 5660,.hw_value = 132,.max_power = 20},
+ {.center_freq = 5680,.hw_value = 136,.max_power = 20},
+ {.center_freq = 5700,.hw_value = 140,.max_power = 20},
+ {.center_freq = 5745,.hw_value = 149,.max_power = 20},
+ {.center_freq = 5765,.hw_value = 153,.max_power = 20},
+ {.center_freq = 5785,.hw_value = 157,.max_power = 20},
+ {.center_freq = 5805,.hw_value = 161,.max_power = 20},
+ {.center_freq = 5825,.hw_value = 165,.max_power = 20},
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern int cfg80211_wext;
+
+struct ieee80211_supported_band cfg80211_band_2ghz = {
+ .channels = cfg80211_channels_2ghz,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_2ghz),
+ .bitrates = cfg80211_rates,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates),
+};
+
+struct ieee80211_supported_band cfg80211_band_5ghz = {
+ .channels = cfg80211_channels_5ghz,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_5ghz),
+ .bitrates = cfg80211_rates + 5,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates) - 5,
+};
+
+#ifndef WLAN_CIPHER_SUITE_SMS4
+#define WLAN_CIPHER_SUITE_SMS4 0x00000020
+#endif
+
+/* Supported crypto cipher suits to be advertised to cfg80211 */
+const u32 cfg80211_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_SMS4,
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Get the private structure from wiphy
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return Pointer to moal_private
+ */
+void *
+woal_get_wiphy_priv(struct wiphy *wiphy)
+{
+ return (void *) (*(unsigned long *) wiphy_priv(wiphy));
+}
+
+/**
+ * @brief Get the private structure from net device
+ *
+ * @param wiphy A pointer to net_device structure
+ *
+ * @return Pointer to moal_private
+ */
+void *
+woal_get_netdev_priv(struct net_device *dev)
+{
+ return (void *) netdev_priv(dev);
+}
+
+/**
+ * @brief Set/Enable encryption key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param is_enable_wep Enable WEP default key
+ * @param cipher Cipher suite selector
+ * @param key A pointer to key
+ * @param key_len Key length
+ * @param seq A pointer to sequence
+ * @param seq_len Sequence length
+ * @param key_index Key index
+ * @param addr Mac for which key is to be set
+ * @param disable Key disabled or not
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep,
+ t_u32 cipher, const t_u8 * key, int key_len,
+ const t_u8 * seq, int seq_len, t_u8 key_index,
+ const t_u8 * addr, int disable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ if (is_enable_wep) {
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else if (!disable) {
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (key && key_len) {
+ priv->key_len = key_len;
+ memcpy(priv->key_material, key, key_len);
+ priv->cipher = cipher;
+ priv->key_index = key_index;
+ }
+ if ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ PRINTM(MIOCTL, "Set WEP key\n");
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ }
+#endif
+#endif
+ if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ cipher != WLAN_CIPHER_SUITE_WEP104 &&
+ cipher != WLAN_CIPHER_SUITE_TKIP &&
+ cipher != WLAN_CIPHER_SUITE_SMS4 &&
+ cipher != WLAN_CIPHER_SUITE_CCMP) {
+ PRINTM(MERROR, "Invalid cipher suite specified\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ sec->param.encrypt_key.key_index = key_index;
+ if (key && key_len) {
+ memcpy(sec->param.encrypt_key.key_material, key, key_len);
+ sec->param.encrypt_key.key_len = key_len;
+ }
+ /* Set WAPI key */
+ if (cipher == WLAN_CIPHER_SUITE_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ if (seq_len) {
+ memcpy(sec->param.encrypt_key.pn, seq, PN_SIZE);
+ DBG_HEXDUMP(MCMD_D, "WAPI PN", sec->param.encrypt_key.pn,
+ seq_len);
+ }
+ }
+ if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ cipher != WLAN_CIPHER_SUITE_WEP104) {
+ if (addr) {
+ memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
+ if (0 ==
+ memcmp(sec->param.encrypt_key.mac_addr, bcast_addr,
+ ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+ } else {
+ memcpy(sec->param.encrypt_key.mac_addr, bcast_addr, ETH_ALEN);
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ }
+ if (seq && seq_len) {
+ memcpy(sec->param.encrypt_key.pn, seq, seq_len);
+ sec->param.encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID;
+ }
+ }
+ } else {
+ if (key_index == KEY_INDEX_CLEAR_ALL)
+ sec->param.encrypt_key.key_disable = MTRUE;
+ else {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ }
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ if (addr)
+ memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Enable the WEP key to driver
+ *
+ * @param priv A pointer to moal_private structure
+ * @param key A pointer to key data
+ * @param key_len Length of the key data
+ * @param index Key index
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cfg80211_set_wep_keys(moal_private * priv, const t_u8 * key, int key_len,
+ t_u8 index)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 cipher = 0;
+
+ ENTER();
+
+ if (key_len) {
+ if (key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ ret =
+ woal_cfg80211_set_key(priv, 0, cipher, key, key_len, NULL, 0, index,
+ NULL, 0);
+ } else {
+ /* No key provided so it is enable key. We want to just set the
+ transmit key index */
+ woal_cfg80211_set_key(priv, 1, cipher, key, key_len, NULL, 0, index,
+ NULL, 0);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/**
+ * @brief set bss role
+ *
+ * @param priv A pointer to moal private structure
+ * @param action Action: set or get
+ * @param role A pointer to bss role
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_bss_role_cfg(moal_private * priv, t_u16 action, t_u8 * bss_role)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (action == MLAN_ACT_SET) {
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_SET) {
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief initialize p2p client for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_init_p2p_client(moal_private * priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ t_u8 bss_role;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when init p2p client\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the bss role */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_role != MLAN_BSS_ROLE_STA) {
+ bss_role = MLAN_BSS_ROLE_STA;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* first, init wifi direct to listen mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* second, init wifi direct client */
+ wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief initialize p2p GO for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_init_p2p_go(moal_private * priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode;
+ t_u8 bss_role;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when init p2p GO\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* first, init wifi direct to listen mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* second, init wifi direct to GO mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_GO;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the bss role, and set it to uAP */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_role != MLAN_BSS_ROLE_UAP) {
+ bss_role = MLAN_BSS_ROLE_UAP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset bss role and wifi direct mode for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_deinit_p2p(moal_private * priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode;
+ t_u8 bss_role;
+ t_u8 channel_status;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when deinit p2p\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg
+ (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+
+ /* get the bss role */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_bss_role_cfg(priv,
+ MLAN_ACT_GET,
+ &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* reset bss role */
+ if (bss_role != MLAN_BSS_ROLE_STA) {
+ bss_role = MLAN_BSS_ROLE_STA;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/**
+ * @brief Request the driver to change the interface type
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param type Virtual interface types
+ * @param flags Flags
+ * @param params A pointer to vif_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type, u32 * flags,
+ struct vif_params *params)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (priv->wdev->iftype == type) {
+ PRINTM(MINFO, "Already set to required type\n");
+ goto done;
+ }
+ PRINTM(MIOCTL, "change virturl intf=%d\n", type);
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /** cancel previous remain on channel to avoid firmware hang */
+ if (priv->phandle->remain_on_channel) {
+ t_u8 channel_status;
+ if (woal_cfg80211_remain_on_channel_cfg
+ (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+#endif
+#endif
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ priv->wdev->iftype = NL80211_IFTYPE_ADHOC;
+ PRINTM(MINFO, "Setting interface type to adhoc\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+ && (priv->wdev->iftype == NL80211_IFTYPE_AP
+ || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO
+ || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ /* if we support wifi direct && priv->bss_type == wifi_direct, and
+ currently the interface type is AP or GO or client, that means
+ wpa_supplicant deinit() wifi direct interface, so we should
+ deinit bss_role and wifi direct mode, for other bss_type, we
+ should not update bss_role and wifi direct mode */
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_deinit_p2p(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->wdev->iftype = NL80211_IFTYPE_STATION;
+ PRINTM(MINFO, "Setting interface type to managed\n");
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ case NL80211_IFTYPE_P2P_CLIENT:
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
+ PRINTM(MINFO, "Setting interface type to P2P client\n");
+
+ break;
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+ case NL80211_IFTYPE_AP:
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ case NL80211_IFTYPE_P2P_GO:
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_go(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (type == NL80211_IFTYPE_P2P_GO)
+ priv->wdev->iftype = NL80211_IFTYPE_P2P_GO;
+#endif
+#endif
+ if (type == NL80211_IFTYPE_AP)
+ priv->wdev->iftype = NL80211_IFTYPE_AP;
+ PRINTM(MINFO, "Setting interface type to P2P GO\n");
+
+ /* there is no need for P2P GO to set bss_mode */
+ goto done;
+
+ break;
+
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ priv->wdev->iftype = NL80211_IFTYPE_STATION;
+ PRINTM(MINFO, "Setting interface type to auto\n");
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the value of fragment
+ * threshold or rts threshold or retry limit
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param changed Change flags
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ mlan_uap_bss_param sys_cfg;
+#endif
+#endif
+ int frag_thr = wiphy->frag_threshold;
+ int rts_thr = wiphy->frag_threshold;
+ int retry = wiphy->retry_long;
+
+ ENTER();
+
+ if (rts_thr == MLAN_FRAG_RTS_DISABLED)
+ rts_thr = MLAN_RTS_MAX_VALUE;
+ if (frag_thr == MLAN_FRAG_RTS_DISABLED)
+ frag_thr = MLAN_FRAG_MAX_VALUE;
+
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+ sys_cfg.frag_threshold = frag_thr;
+ sys_cfg.rts_threshold = rts_thr;
+ sys_cfg.retry_limit = retry;
+
+ if ((changed & WIPHY_PARAM_RTS_THRESHOLD) ||
+ (changed & WIPHY_PARAM_FRAG_THRESHOLD) ||
+ (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))) {
+ if (woal_set_get_sys_config(priv,
+ MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &sys_cfg))
+ goto fail;
+ }
+ }
+#endif
+#endif
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ if (woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rts_thr))
+ goto fail;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ if (woal_set_get_frag
+ (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &frag_thr))
+ goto fail;
+ }
+ if (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))
+ if (woal_set_get_retry(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &retry))
+ goto fail;
+ }
+#endif
+#endif
+
+ LEAVE();
+ return 0;
+
+ fail:
+ PRINTM(MERROR, "Failed to change wiphy params %x\n", changed);
+ LEAVE();
+ return -EFAULT;
+}
+
+/**
+ * @brief Request the driver to add a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36)
+ * @param mac_addr MAC address (NULL for group key)
+ * @param params A pointer to key_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr, struct key_params *params)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev);
+
+ ENTER();
+
+ if (woal_cfg80211_set_key(priv, 0, params->cipher, params->key,
+ params->key_len, params->seq, params->seq_len,
+ key_index, mac_addr, 0)) {
+ PRINTM(MERROR, "Error adding the crypto keys\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Crypto keys added\n");
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to delete a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36)
+ * @param mac_addr MAC address (NULL for group key)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev);
+
+ ENTER();
+
+ if (woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, key_index,
+ mac_addr, 1)) {
+ PRINTM(MERROR, "Error deleting the crypto keys\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Crypto keys deleted\n");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request to enable WEP key to driver
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param ucast Unicast flag (for kernel > 2.6.37)
+ * @param mcast Multicast flag (for kernel > 2.6.37)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *netdev, t_u8 key_index
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ , bool ucast, bool mcast
+#endif
+ )
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev);
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.wep_status) {
+ LEAVE();
+ return ret;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, NULL, 0, key_index)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_channel(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS)
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ int ret = 0;
+ moal_private *priv = NULL;
+
+ ENTER();
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS)
+ if (dev)
+ priv = woal_get_netdev_priv(dev);
+ else
+#endif
+ priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MERROR, "This configuration is valid only when station "
+ "is not connected\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ ret = woal_set_rf_channel(priv, chan, channel_type);
+ }
+#endif
+#endif
+ priv->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief register/unregister mgmt frame forwarding
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param frame_type Bit mask for mgmt frame type
+ * @param reg Register or unregister
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void
+woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev, u16 frame_type,
+ bool reg)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mgmt_subtype_mask = 0x0;
+ static t_u32 last_mgmt_subtype_mask = 0x0;
+
+ ENTER();
+#ifdef UAP_SUPPORT
+ if ((priv->bss_type == MLAN_BSS_TYPE_UAP) &&
+ (frame_type == IEEE80211_STYPE_PROBE_REQ)) {
+ LEAVE();
+ return;
+ }
+#endif
+ if (reg == MTRUE) {
+ /* set mgmt_subtype_mask based on origin value */
+ last_mgmt_subtype_mask |= BIT(frame_type >> 4);
+ } else {
+ /* clear mgmt_subtype_mask */
+ last_mgmt_subtype_mask &= ~BIT(frame_type >> 4);
+ }
+ mgmt_subtype_mask = last_mgmt_subtype_mask;
+
+ /* Notify driver that a mgmt frame type was registered. Note that this
+ callback may not sleep, and cannot run concurrently with itself. */
+ status = woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
+ &mgmt_subtype_mask, MOAL_NO_WAIT);
+
+ LEAVE();
+}
+
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param channel_type Channel type
+ * @param channel_type_valid Is channel type valid or not
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan, bool offchan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid, unsigned int wait,
+ const u8 * buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ bool no_cck,
+#endif
+ u64 * cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+ pmlan_buffer pmbuf = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u16 packet_len = 0;
+ t_u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ t_u16 framectrl;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ t_u8 channel_status;
+ t_u32 duration;
+#endif
+#endif
+
+ ENTER();
+
+ if (buf == NULL || len == 0) {
+ PRINTM(MERROR, "woal_cfg80211_mgmt_tx() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* frame subtype == probe response, that means we are in listen phase, so
+ we should not call remain_on_channel_cfg because remain_on_channl
+ already handled it. frame subtype == action, that means we are in
+ PD/GO negotiation, so we should call remain_on_channel_cfg in order to
+ receive action frame from peer device */
+ framectrl = ((const struct ieee80211_mgmt *) buf)->frame_control;
+ PRINTM(MIOCTL, "Mgmt: framectrl=0x%x\n", framectrl);
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if ((priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (framectrl == IEEE80211_STYPE_ACTION)) {
+#define MGMT_TX_DEFAULT_WAIT_TIME 2000
+ /** cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg
+ (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ duration = wait;
+ if (!wait)
+ duration = MGMT_TX_DEFAULT_WAIT_TIME;
+ if (channel_type_valid)
+ ret =
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
+ MFALSE, &channel_status,
+ chan, channel_type,
+ duration);
+ else
+ ret =
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
+ MFALSE, &channel_status,
+ chan, 0, duration);
+ if (ret) {
+ PRINTM(MERROR, "Fail to configure remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->channel_type = channel_type;
+ memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel));
+ PRINTM(MIOCTL, "Mgmt Tx: Set remain channel=%d\n",
+ ieee80211_frequency_to_channel(chan->center_freq));
+ }
+#endif
+#endif
+#define MRVL_PKT_TYPE_MGMT_FRAME 0xE5
+ /* pkt_type + tx_control */
+#define HEADER_SIZE 8
+ packet_len = (t_u16) len + MLAN_MAC_ADDR_LENGTH;
+ pmbuf = woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
+ packet_len + sizeof(packet_len));
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ *cookie = random32() | 1;
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+ pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
+ tx_control = 0;
+ /* Add pkt_type and tx_control */
+ memcpy(pmbuf->pbuf + pmbuf->data_offset, &pkt_type, sizeof(pkt_type));
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), &tx_control,
+ sizeof(tx_control));
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
+#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &packet_len,
+ sizeof(packet_len));
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len),
+ buf, PACKET_ADDR4_POS);
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len)
+ + PACKET_ADDR4_POS, addr, MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len)
+ + PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH,
+ buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS);
+
+ pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* delay 20ms to guarantee the packet has been already tx'ed becuase if
+ we call cfg80211_mgmt_tx_status() immediately, then wpa_supplicant
+ will call cancel_remain_on_channel(), which may affect the mgmt
+ frame tx */
+ mdelay(20);
+
+ /* Notify the mgmt tx status */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_ATOMIC);
+#endif
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Look up specific IE in a buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param id Element id to lookup
+ *
+ * @return Pointer of the specific IE -- success, NULL -- fail
+ */
+const t_u8 *
+woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+
+ /* IE format: | u8 | id | | u8 | len | | var | data | */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ if ((*pos == id) && (length + 2) <= left_len)
+ return pos;
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief This function returns priv
+ * based on mgmt ie index
+ *
+ * @param handle A pointer to moal_handle
+ * @param index mgmt ie index
+ *
+ * @return Pointer to moal_private
+ */
+static moal_private *
+woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (handle->priv[i]->probereq_index == index)
+ return (handle->priv[i]);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief Add custom ie to mgmt frames.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies_data Beacon ie
+ * @param beacon_index The index for beacon when auto index
+ * @param proberesp_ies_data Probe resp ie
+ * @param proberesp_index The index for probe resp when auto index
+ * @param assocresp_ies_data Assoc resp ie
+ * @param assocresp_index The index for assoc resp when auto index
+ * @param probereq_ies_data Probe req ie
+ * @param probereq_index The index for probe req when auto index *
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_custom_ie(moal_private * priv,
+ custom_ie * beacon_ies_data, t_u16 * beacon_index,
+ custom_ie * proberesp_ies_data, t_u16 * proberesp_index,
+ custom_ie * assocresp_ies_data, t_u16 * assocresp_index,
+ custom_ie * probereq_ies_data, t_u16 * probereq_index)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ t_u8 *pos = NULL;
+ t_u16 len = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie));
+ custom_ie->type = TLV_TYPE_MGMT_IE;
+
+ pos = (t_u8 *) custom_ie->ie_data_list;
+ if (beacon_ies_data) {
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
+ + beacon_ies_data->ie_length;
+ memcpy(pos, beacon_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ if (proberesp_ies_data) {
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
+ + proberesp_ies_data->ie_length;
+ memcpy(pos, proberesp_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ if (assocresp_ies_data) {
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
+ + assocresp_ies_data->ie_length;
+ memcpy(pos, assocresp_ies_data, len);
+ custom_ie->len += len;
+ }
+
+ if (probereq_ies_data) {
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
+ + probereq_ies_data->ie_length;
+ memcpy(pos, probereq_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the assigned index */
+ pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index);
+ if (beacon_ies_data && beacon_ies_data->ie_length
+ && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save beacon ie index after auto-indexing */
+ *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
+ + beacon_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (proberesp_ies_data && proberesp_ies_data->ie_length
+ && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *proberesp_index = *((t_u16 *) pos);
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
+ + proberesp_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (assocresp_ies_data && assocresp_ies_data->ie_length
+ && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save assoc resp ie index after auto-indexing */
+ *assocresp_index = *((t_u16 *) pos);
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
+ + assocresp_ies_data->ie_length;
+ pos += len;
+ }
+ if (probereq_ies_data && probereq_ies_data->ie_length
+ && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *probereq_index = *((t_u16 *) pos);
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
+ + probereq_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
+ ret = -EFAULT;
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ if (custom_ie)
+ kfree(custom_ie);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Filter specific IE in ie buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param ie_out Pointer to out IE buf
+ *
+ * @return out IE length
+ */
+static t_u16
+woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+ t_u16 out_len = 0;
+
+ /* ERP_INFO and RSN IE will be fileter out */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ switch (id) {
+ case WLAN_EID_ERP_INFO:
+ case RSN_IE:
+ break;
+ default:
+ memcpy(ie_out + out_len, pos, length + 2);
+ out_len += length + 2;
+ break;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ return out_len;
+}
+
+/**
+ * @brief config AP or GO for mgmt frame ies.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies A pointer to beacon ies
+ * @param beacon_ies_len Beacon ies length
+ * @param proberesp_ies A pointer to probe resp ies
+ * @param proberesp_ies_len Probe resp ies length
+ * @param assocresp_ies A pointer to probe resp ies
+ * @param assocresp_ies_len Assoc resp ies length
+ * @param probereq_ies A pointer to probe req ies
+ * @param probereq_ies_len Probe req ies length *
+ * @param mask Mgmt frame mask
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_mgmt_frame_ie(moal_private * priv,
+ const t_u8 * beacon_ies, size_t beacon_ies_len,
+ const t_u8 * proberesp_ies,
+ size_t proberesp_ies_len,
+ const t_u8 * assocresp_ies,
+ size_t assocresp_ies_len, const t_u8 * probereq_ies,
+ size_t probereq_ies_len, t_u16 mask)
+{
+ int ret = 0;
+ t_u8 *pos = NULL;
+ custom_ie *beacon_ies_data = NULL;
+ custom_ie *proberesp_ies_data = NULL;
+ custom_ie *assocresp_ies_data = NULL;
+ custom_ie *probereq_ies_data = NULL;
+
+ /* static variables for mgmt frame ie auto-indexing */
+ static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ moal_private *pmpriv = NULL;
+ static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ const t_u8 *rsn_ie;
+
+ ENTER();
+
+ if (mask & MGMT_MASK_BEACON) {
+ if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (beacon_ies && beacon_ies_len) {
+ rsn_ie =
+ woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len,
+ RSN_IE);
+ if (rsn_ie) {
+ beacon_ies_data->ie_index = rsn_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP;
+ beacon_ies_data->ie_length = rsn_ie[1] + 2;
+ memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ /* clear rsn_ie */
+ if (rsn_index <= MAX_MGMT_IE_INDEX) {
+ beacon_ies_data->ie_index = rsn_index;
+ beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (mask & MGMT_MASK_PROBE_RESP) {
+ if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (mask & MGMT_MASK_ASSOC_RESP) {
+ if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ if (mask & MGMT_MASK_PROBE_REQ) {
+ if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (beacon_ies_data) {
+ memset(beacon_ies_data, 0x00, sizeof(custom_ie));
+ if (beacon_ies && beacon_ies_len) {
+ /* set the beacon ies */
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
+ beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP;
+ beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies,
+ beacon_ies_len,
+ beacon_ies_data->
+ ie_buffer);
+ } else {
+ /* clear the beacon ies */
+ if (beacon_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (proberesp_ies_data) {
+ memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
+ if (proberesp_ies && proberesp_ies_len) {
+ /* set the probe response ies */
+ // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP;
+ proberesp_ies_data->ie_length = proberesp_ies_len;
+ pos = proberesp_ies_data->ie_buffer;
+ memcpy(pos, proberesp_ies, proberesp_ies_len);
+ } else {
+ /* clear the probe response ies */
+ if (proberesp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ proberesp_ies_data->ie_length = 0;
+ proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+ if (assocresp_ies_data) {
+ memset(assocresp_ies_data, 0x00, sizeof(custom_ie));
+ if (assocresp_ies && assocresp_ies_len) {
+ /* set the assoc response ies */
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP;
+ assocresp_ies_data->ie_length = assocresp_ies_len;
+ pos = assocresp_ies_data->ie_buffer;
+ memcpy(pos, assocresp_ies, assocresp_ies_len);
+ } else {
+ /* clear the assoc response ies */
+ if (assocresp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ assocresp_ies_data->ie_length = 0;
+ assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (probereq_ies_data) {
+ memset(probereq_ies_data, 0x00, sizeof(custom_ie));
+ if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) &&
+ (priv->probereq_index != probereq_index)) {
+ pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index);
+ if (pmpriv) {
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index,
+ NULL, &proberesp_index,
+ NULL, &assocresp_index,
+ probereq_ies_data,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(probereq_ies_data, 0x00, sizeof(custom_ie));
+ }
+ }
+ if (probereq_ies && probereq_ies_len) {
+ /* set the probe req ies */
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ;
+ probereq_ies_data->ie_length = probereq_ies_len;
+ pos = probereq_ies_data->ie_buffer;
+ memcpy(pos, probereq_ies, probereq_ies_len);
+ } else {
+ /* clear the probe req ies */
+ if (probereq_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index,
+ proberesp_ies_data, &proberesp_index,
+ assocresp_ies_data, &assocresp_index,
+ probereq_ies_data, &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (probereq_ies_data)
+ priv->probereq_index = probereq_index;
+
+ done:
+ if (beacon_ies_data)
+ kfree(beacon_ies_data);
+ if (proberesp_ies_data)
+ kfree(proberesp_ies_data);
+ if (assocresp_ies_data)
+ kfree(assocresp_ies_data);
+
+ LEAVE();
+
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
new file mode 100644
index 000000000000..f58fc18829fa
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
@@ -0,0 +1,203 @@
+/** @file moal_cfg80211.h
+ *
+ * @brief This file contains the CFG80211 specific defines.
+ *
+ * Copyright (C) 2011-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.
+ *
+ */
+
+#ifndef _MOAL_CFG80211_H_
+#define _MOAL_CFG80211_H_
+
+#include "moal_main.h"
+
+/* Clear all key indexes */
+#define KEY_INDEX_CLEAR_ALL (0x0000000F)
+
+/** RTS/FRAG disabled value */
+#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF)
+
+#ifndef WLAN_CIPHER_SUITE_WAPI
+#define WLAN_CIPHER_SUITE_WAPI 0x00000020
+#endif
+
+/* define for custom ie operation */
+#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
+#define MLAN_CUSTOM_IE_DELETE_MASK 0x0
+#define TLV_TYPE_MGMT_IE 0x0169
+#define MGMT_MASK_ASSOC_REQ 0x01
+#define MGMT_MASK_REASSOC_REQ 0x04
+#define MGMT_MASK_ASSOC_RESP 0x02
+#define MGMT_MASK_REASSOC_RESP 0x08
+#define MGMT_MASK_PROBE_REQ 0x10
+#define MGMT_MASK_PROBE_RESP 0x20
+#define MGMT_MASK_BEACON 0x100
+
+/**
+ * If multiple wiphys are registered e.g. a regular netdev with
+ * assigned ieee80211_ptr and you won't know whether it points
+ * to a wiphy your driver has registered or not. Assign this to
+ * something global to your driver to help determine whether
+ * you own this wiphy or not.
+ */
+static const void *const mrvl_wiphy_privid = &mrvl_wiphy_privid;
+
+/* Get the private structure from wiphy */
+void *woal_get_wiphy_priv(struct wiphy *wiphy);
+
+/* Get the private structure from net device */
+void *woal_get_netdev_priv(struct net_device *dev);
+
+int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params);
+
+int woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+int woal_cfg80211_add_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr, struct key_params *params);
+
+int woal_cfg80211_del_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr);
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+int woal_set_rf_channel(moal_private * priv,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
+mlan_status woal_inform_bss_from_scan_result(moal_private * priv,
+ mlan_802_11_ssid * ssid);
+#endif
+#endif
+
+int woal_cfg80211_set_channel(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS)
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+int woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index,
+ bool ucast, bool mcast);
+#else
+int woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index);
+#endif
+
+void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev, t_u16 frame_type,
+ bool reg);
+
+int woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan, bool offchan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid, unsigned int wait,
+ const u8 * buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ bool no_cck,
+#endif
+ u64 * cookie);
+
+extern struct ieee80211_supported_band cfg80211_band_2ghz;
+extern struct ieee80211_supported_band cfg80211_band_5ghz;
+extern const u32 cfg80211_cipher_suites[10];
+
+typedef struct _monitor_iface
+{
+ /* The priv data of interface on which the monitor iface is based */
+ moal_private *priv;
+ struct wireless_dev wdev;
+ int radiotap_enabled;
+ /* The net_device on which the monitor iface is based. */
+ struct net_device *base_ndev;
+ struct net_device *mon_ndev;
+ char ifname[IFNAMSIZ];
+ int flag;
+} monitor_iface;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+struct net_device *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name,
+ enum nl80211_iftype type,
+ u32 * flags,
+ struct vif_params *params);
+#else
+int woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params);
+#endif
+int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Define kernel version for wifi direct */
+#if !defined(COMPAT_WIRELESS)
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,39)
+#else
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,33)
+#endif /* COMPAT_WIRELESS */
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/** Define for remain on channel duration timer */
+#define MAX_REMAIN_ON_CHANNEL_DURATION (1000 * 5)
+
+int woal_cfg80211_add_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_set_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev);
+
+int woal_cfg80211_init_p2p_client(moal_private * priv);
+
+int woal_cfg80211_init_p2p_go(moal_private * priv);
+
+int woal_cfg80211_deinit_p2p(moal_private * priv);
+
+int woal_cfg80211_remain_on_channel_cfg(moal_private * priv,
+ t_u8 wait_option, t_u8 remove,
+ t_u8 * status,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ t_u32 duration);
+int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 * mac, struct station_info *stainfo);
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+const t_u8 *woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id);
+
+int woal_cfg80211_mgmt_frame_ie(moal_private * priv,
+ const t_u8 * beacon_ies, size_t beacon_ies_len,
+ const t_u8 * proberesp_ies,
+ size_t proberesp_ies_len,
+ const t_u8 * assocresp_ies,
+ size_t assocresp_ies_len,
+ const t_u8 * probereq_ies,
+ size_t probereq_ies_len, t_u16 mask);
+#endif /* _MOAL_CFG80211_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_debug.c b/drivers/net/wireless/sd8797/mlinux/moal_debug.c
new file mode 100644
index 000000000000..fd74c3b5ae92
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_debug.c
@@ -0,0 +1,674 @@
+/** @file moal_debug.c
+ *
+ * @brief This file contains functions for debug proc file.
+ *
+ * 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/03/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+/** MLAN debug info */
+extern mlan_debug_info info;
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+
+/** Get info item size */
+#define item_size(n) (sizeof(info.n))
+/** Get info item address */
+#define item_addr(n) ((t_ptr) &(info.n))
+
+/** Get moal_private member size */
+#define item_priv_size(n) (sizeof ((moal_private *)0)->n)
+/** Get moal_private member address */
+#define item_priv_addr(n) ((t_ptr) &((moal_private *)0)->n)
+
+/** Get moal_handle member size */
+#define item_handle_size(n) (sizeof ((moal_handle *)0)->n)
+/** Get moal_handle member address */
+#define item_handle_addr(n) ((t_ptr) &((moal_handle *)0)->n)
+
+#ifdef STA_SUPPORT
+static struct debug_data items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(drvdbg), (t_ptr) & drvdbg}
+ ,
+#endif
+ {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo)}
+ ,
+ {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi)}
+ ,
+ {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be)}
+ ,
+ {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk)}
+ ,
+ {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)}
+ ,
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)}
+ ,
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size)}
+ ,
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode)}
+ ,
+ {"ps_state", item_size(ps_state), item_addr(ps_state)}
+ ,
+ {"is_deep_sleep", item_size(is_deep_sleep), item_addr(is_deep_sleep)}
+ ,
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req)}
+ ,
+ {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)}
+ ,
+ {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)}
+ ,
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated)}
+ ,
+ {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued)}
+ ,
+ {"pps_uapsd_mode", item_size(pps_uapsd_mode), item_addr(pps_uapsd_mode)}
+ ,
+ {"sleep_pd", item_size(sleep_pd), item_addr(sleep_pd)}
+ ,
+ {"qos_cfg", item_size(qos_cfg), item_addr(qos_cfg)}
+ ,
+ {"tx_lock_flag", item_size(tx_lock_flag), item_addr(tx_lock_flag)}
+ ,
+ {"port_open", item_size(port_open), item_addr(port_open)}
+ ,
+ {"scan_processing", item_size(scan_processing), item_addr(scan_processing)}
+ ,
+ {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)}
+ ,
+ {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)}
+ ,
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)}
+ ,
+ {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)}
+ ,
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)}
+ ,
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)}
+ ,
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)}
+ ,
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id)}
+ ,
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index)}
+ ,
+ {"last_event", item_size(last_event), item_addr(last_event)}
+ ,
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index)}
+ ,
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure)}
+ ,
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure)}
+ ,
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure)}
+ ,
+ {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure),
+ item_addr(num_cmdevt_card_to_host_failure)}
+ ,
+ {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure),
+ item_addr(num_rx_card_to_host_failure)}
+ ,
+ {"num_int_read_fail", item_size(num_int_read_failure),
+ item_addr(num_int_read_failure)}
+ ,
+ {"last_int_status", item_size(last_int_status), item_addr(last_int_status)}
+ ,
+ {"num_evt_deauth", item_size(num_event_deauth), item_addr(num_event_deauth)}
+ ,
+ {"num_evt_disassoc", item_size(num_event_disassoc),
+ item_addr(num_event_disassoc)}
+ ,
+ {"num_evt_link_lost", item_size(num_event_link_lost),
+ item_addr(num_event_link_lost)}
+ ,
+ {"num_cmd_deauth", item_size(num_cmd_deauth), item_addr(num_cmd_deauth)}
+ ,
+ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+ item_addr(num_cmd_assoc_success)}
+ ,
+ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+ item_addr(num_cmd_assoc_failure)}
+ ,
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)}
+ ,
+ {"data_sent", item_size(data_sent), item_addr(data_sent)}
+ ,
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)}
+ ,
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)}
+ ,
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)}
+ ,
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)}
+ ,
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received)}
+ ,
+ {"event_received", item_size(event_received), item_addr(event_received)}
+ ,
+
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending)}
+ ,
+ {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)}
+ ,
+ {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)}
+ ,
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count)}
+ ,
+ {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)}
+ ,
+ {"mbufalloc_count", item_handle_size(mbufalloc_count),
+ item_handle_addr(mbufalloc_count)}
+ ,
+ {"main_state", item_handle_size(main_state), item_handle_addr(main_state)}
+ ,
+#ifdef SDIO_MMC_DEBUG
+ {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w)}
+ ,
+ {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r)}
+ ,
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ {"hs_skip_count", item_handle_size(hs_skip_count),
+ item_handle_addr(hs_skip_count)}
+ ,
+ {"hs_force_count", item_handle_size(hs_force_count),
+ item_handle_addr(hs_force_count)}
+ ,
+#endif
+};
+
+#endif
+
+#ifdef UAP_SUPPORT
+static struct debug_data uap_items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(drvdbg), (t_ptr) & drvdbg}
+ ,
+#endif
+ {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo)}
+ ,
+ {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi)}
+ ,
+ {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be)}
+ ,
+ {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk)}
+ ,
+ {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)}
+ ,
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)}
+ ,
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size)}
+ ,
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode)}
+ ,
+ {"ps_state", item_size(ps_state), item_addr(ps_state)}
+ ,
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req)}
+ ,
+ {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)}
+ ,
+ {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)}
+ ,
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated)}
+ ,
+ {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued)}
+ ,
+ {"num_bridge_pkts", item_size(num_bridge_pkts), item_addr(num_bridge_pkts)}
+ ,
+ {"num_drop_pkts", item_size(num_drop_pkts), item_addr(num_drop_pkts)}
+ ,
+ {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)}
+ ,
+ {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)}
+ ,
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)}
+ ,
+ {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)}
+ ,
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)}
+ ,
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)}
+ ,
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)}
+ ,
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id)}
+ ,
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index)}
+ ,
+ {"last_event", item_size(last_event), item_addr(last_event)}
+ ,
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index)}
+ ,
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure)}
+ ,
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure)}
+ ,
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure)}
+ ,
+ {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure),
+ item_addr(num_cmdevt_card_to_host_failure)}
+ ,
+ {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure),
+ item_addr(num_rx_card_to_host_failure)}
+ ,
+ {"num_int_read_fail", item_size(num_int_read_failure),
+ item_addr(num_int_read_failure)}
+ ,
+ {"last_int_status", item_size(last_int_status), item_addr(last_int_status)}
+ ,
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)}
+ ,
+ {"data_sent", item_size(data_sent), item_addr(data_sent)}
+ ,
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)}
+ ,
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)}
+ ,
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)}
+ ,
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)}
+ ,
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received)}
+ ,
+ {"event_received", item_size(event_received), item_addr(event_received)}
+ ,
+
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending)}
+ ,
+ {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)}
+ ,
+ {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)}
+ ,
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count)}
+ ,
+ {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)}
+ ,
+ {"mbufalloc_count", item_handle_size(mbufalloc_count),
+ item_handle_addr(mbufalloc_count)}
+ ,
+ {"main_state", item_handle_size(main_state), item_handle_addr(main_state)}
+ ,
+#ifdef SDIO_MMC_DEBUG
+ {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w)}
+ ,
+ {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r)}
+ ,
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ {"hs_skip_count", item_handle_size(hs_skip_count),
+ item_handle_addr(hs_skip_count)}
+ ,
+ {"hs_force_count", item_handle_size(hs_force_count),
+ item_handle_addr(hs_force_count)}
+ ,
+#endif
+};
+#endif /* UAP_SUPPORT */
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function
+ *
+ * @param page Pointer to buffer
+ * @param s Read data starting position
+ * @param off Offset
+ * @param cnt Counter
+ * @param eof End of file flag
+ * @param data Output data
+ *
+ * @return Number of output data or MLAN_STATUS_FAILURE
+ */
+static int
+woal_debug_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
+{
+ int val = 0;
+ unsigned int i;
+ char *p = page;
+ struct debug_data *d = ((struct debug_data_priv *) data)->items;
+ moal_private *priv = ((struct debug_data_priv *) data)->priv;
+
+ ENTER();
+
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Get debug information */
+ if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ *eof = 1;
+ goto exit;
+ }
+ for (i = 0;
+ i < (unsigned int) ((struct debug_data_priv *) data)->num_of_items;
+ i++) {
+ if (d[i].size == 1)
+ val = *((t_u8 *) d[i].addr);
+ else if (d[i].size == 2)
+ val = *((t_u16 *) d[i].addr);
+ else if (d[i].size == 4)
+ val = *((t_ptr *) d[i].addr);
+ else {
+ unsigned int j;
+ p += sprintf(p, "%s=", d[i].name);
+ for (j = 0; j < d[i].size; j += 2) {
+ val = *(t_u16 *) (d[i].addr + j);
+ p += sprintf(p, "0x%x ", val);
+ }
+ p += sprintf(p, "\n");
+ continue;
+ }
+ if (strstr(d[i].name, "id") || strstr(d[i].name, "bitmap"))
+ p += sprintf(p, "%s=0x%x\n", d[i].name, val);
+ else
+ p += sprintf(p, "%s=%d\n", d[i].name, val);
+ }
+ if (info.tx_tbl_num) {
+ p += sprintf(p, "Tx BA stream table:\n");
+ for (i = 0; i < info.tx_tbl_num; i++) {
+ p += sprintf(p,
+ "tid = %d, ra = %02x:%02x:%02x:%02x:%02x:%02x amsdu=%d\n",
+ (int) info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
+ info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
+ info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
+ info.tx_tbl[i].ra[5], (int) info.tx_tbl[i].amsdu);
+ }
+ }
+ if (info.rx_tbl_num) {
+ p += sprintf(p, "Rx reorder table:\n");
+ for (i = 0; i < info.rx_tbl_num; i++) {
+ unsigned int j;
+
+ p += sprintf(p,
+ "tid = %d, ta = %02x:%02x:%02x:%02x:%02x:%02x, start_win = %d, "
+ "win_size = %d, amsdu=%d\n", (int) info.rx_tbl[i].tid,
+ info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
+ info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
+ info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
+ (int) info.rx_tbl[i].start_win,
+ (int) info.rx_tbl[i].win_size,
+ (int) info.rx_tbl[i].amsdu);
+ p += sprintf(p, "buffer: ");
+ for (j = 0; j < info.rx_tbl[i].win_size; j++) {
+ if (info.rx_tbl[i].buffer[j] == MTRUE)
+ p += sprintf(p, "1 ");
+ else
+ p += sprintf(p, "0 ");
+ }
+ p += sprintf(p, "\n");
+ }
+ }
+ exit:
+ MODULE_PUT;
+ LEAVE();
+ return p - page;
+}
+
+/**
+ * @brief Proc write function
+ *
+ * @param f File pointer
+ * @param buf Pointer to data buffer
+ * @param cnt Data number to write
+ * @param data Data to write
+ *
+ * @return Number of data or MLAN_STATUS_FAILURE
+ */
+static int
+woal_debug_write(struct file *f, const char *buf, unsigned long cnt, void *data)
+{
+ int r, i;
+ char *pdata;
+ char *p;
+ char *p0;
+ char *p1;
+ char *p2;
+ struct debug_data *d = ((struct debug_data_priv *) data)->items;
+ moal_private *priv = ((struct debug_data_priv *) data)->priv;
+#ifdef DEBUG_LEVEL1
+ t_u32 last_drvdbg = drvdbg;
+#endif
+
+ ENTER();
+
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pdata = (char *) kmalloc(cnt, GFP_KERNEL);
+ if (pdata == NULL) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ if (copy_from_user(pdata, buf, cnt)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ kfree(pdata);
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ kfree(pdata);
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ p0 = pdata;
+ for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) {
+ do {
+ p = strstr(p0, d[i].name);
+ if (p == NULL)
+ break;
+ p1 = strchr(p, '\n');
+ if (p1 == NULL)
+ break;
+ p0 = p1++;
+ p2 = strchr(p, '=');
+ if (!p2)
+ break;
+ p2++;
+ r = woal_string_to_number(p2);
+ if (d[i].size == 1)
+ *((t_u8 *) d[i].addr) = (t_u8) r;
+ else if (d[i].size == 2)
+ *((t_u16 *) d[i].addr) = (t_u16) r;
+ else if (d[i].size == 4)
+ *((t_ptr *) d[i].addr) = (t_ptr) r;
+ break;
+ } while (MTRUE);
+ }
+ kfree(pdata);
+
+#ifdef DEBUG_LEVEL1
+ if (last_drvdbg != drvdbg)
+ woal_set_drvdbg(priv, drvdbg);
+#endif
+
+ /* Set debug information */
+ if (woal_set_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ MODULE_PUT;
+ LEAVE();
+ return cnt;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Create debug proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_debug_entry(moal_private * priv)
+{
+ struct proc_dir_entry *r;
+
+ ENTER();
+
+ if (priv->proc_entry == NULL) {
+ LEAVE();
+ return;
+ }
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->items_priv.items =
+ (struct debug_data *) kmalloc(sizeof(items), GFP_KERNEL);
+ if (!priv->items_priv.items) {
+ PRINTM(MERROR, "Failed to allocate memory for debug data\n");
+ LEAVE();
+ return;
+ }
+ memcpy(priv->items_priv.items, items, sizeof(items));
+ priv->items_priv.num_of_items = sizeof(items) / sizeof(items[0]);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ priv->items_priv.items =
+ (struct debug_data *) kmalloc(sizeof(uap_items), GFP_KERNEL);
+ if (!priv->items_priv.items) {
+ PRINTM(MERROR, "Failed to allocate memory for debug data\n");
+ LEAVE();
+ return;
+ }
+ memcpy(priv->items_priv.items, uap_items, sizeof(uap_items));
+ priv->items_priv.num_of_items =
+ sizeof(uap_items) / sizeof(uap_items[0]);
+ }
+#endif
+ priv->items_priv.priv = priv;
+ priv->items_priv.items[priv->items_priv.num_of_items - 1].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 2].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 3].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 4].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 5].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 6].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 7].addr +=
+ (t_ptr) (priv->phandle);
+#ifdef SDIO_MMC_DEBUG
+ priv->items_priv.items[priv->items_priv.num_of_items - 8].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 9].addr +=
+ (t_ptr) (priv->phandle);
+#ifdef SDIO_SUSPEND_RESUME
+ priv->items_priv.items[priv->items_priv.num_of_items - 10].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 11].addr +=
+ (t_ptr) (priv->phandle);
+#endif
+#else
+#if defined(SDIO_SUSPEND_RESUME)
+ priv->items_priv.items[priv->items_priv.num_of_items - 8].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 9].addr +=
+ (t_ptr) (priv->phandle);
+#endif
+#endif
+
+ /* Create proc entry */
+ r = create_proc_entry("debug", 0644, priv->proc_entry);
+ if (r == NULL) {
+ LEAVE();
+ return;
+ }
+ r->data = &priv->items_priv;
+ r->read_proc = woal_debug_read;
+ r->write_proc = woal_debug_write;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ r->owner = THIS_MODULE;
+#endif
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_debug_remove(moal_private * priv)
+{
+ ENTER();
+
+ if (priv->items_priv.items)
+ kfree(priv->items_priv.items);
+ /* Remove proc entry */
+ remove_proc_entry("debug", priv->proc_entry);
+
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
new file mode 100644
index 000000000000..31040a29ceec
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
@@ -0,0 +1,2176 @@
+/** @file moal_eth_ioctl.c
+ *
+ * @brief This file contains private ioctl functions
+ *
+ * Copyright (C) 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:
+ 01/05/2012: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_eth_ioctl.h"
+#include "mlan_ioctl.h"
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#include "moal_priv.h"
+#endif
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Marvell private command identifier string */
+#define CMD_MARVELL "MRVL_CMD"
+
+/** Private command: Version */
+#define PRIV_CMD_VERSION "version"
+/** Private command: Band cfg */
+#define PRIV_CMD_BANDCFG "bandcfg"
+/** Private command: Host cmd */
+#define PRIV_CMD_HOSTCMD "hostcmd"
+/** Private command: Custom IE config*/
+#define PRIV_CMD_CUSTOMIE "customie"
+/** Private command: HT Tx Cfg */
+#define PRIV_CMD_HTTXCFG "httxcfg"
+#define PRIV_CMD_DATARATE "getdatarate"
+#define PRIV_CMD_TXRATECFG "txratecfg"
+#define PRIV_CMD_ESUPPMODE "esuppmode"
+#define PRIV_CMD_PASSPHRASE "passphrase"
+#define PRIV_CMD_DEAUTH "deauth"
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#define PRIV_CMD_BSSROLE "bssrole"
+#endif
+#endif
+#ifdef STA_SUPPORT
+#define PRIV_CMD_SETUSERSCAN "setuserscan"
+#endif
+#define PRIV_CMD_DEEPSLEEP "deepsleep"
+#define PRIV_CMD_IPADDR "ipaddr"
+#define PRIV_CMD_WPSSESSION "wpssession"
+#define PRIV_CMD_OTPUSERDATA "otpuserdata"
+#define PRIV_CMD_COUNTRYCODE "countrycode"
+#define PRIV_CMD_TCPACKENH "tcpackenh"
+
+/** Bands supported in Infra mode */
+static t_u8 SupportedInfraBand[] = {
+ BAND_B,
+ BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B, BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A,
+ BAND_AN, BAND_A | BAND_AN,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Parse a string to extract arguments
+ *
+ * @param pos Pointer to the arguments string
+ * @param data Pointer to the arguments buffer
+ * @param user_data_len Pointer to the number of arguments extracted
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ * N.B. No boundary check is done on 'data'. The caller must ensure there
+ * are enough space for all extracted arguments.
+ */
+mlan_status
+parse_arguments(t_u8 * pos, int *data, int *user_data_len)
+{
+ unsigned int i, j, k;
+ char cdata[10];
+ int is_hex = 0;
+
+ memset(cdata, 0, sizeof(cdata));
+ for (i = 0, j = 0, k = 0; i <= strlen(pos); i++) {
+ if ((k == 0) && (i <= (strlen(pos) - 2))) {
+ if ((pos[i] == '0') && (pos[i + 1] == 'x')) {
+ is_hex = 1;
+ i = i + 2;
+ }
+ }
+ if (pos[i] == '\0') {
+ if (is_hex) {
+ data[j] = woal_atox(cdata);
+ is_hex = 0;
+ } else {
+ woal_atoi(&data[j], cdata);
+ }
+ j++;
+ (*user_data_len)++;
+ k = 0;
+ memset(cdata, 0, sizeof(char) * 4);
+ break;
+ } else if (pos[i] == ' ') {
+ if (is_hex) {
+ data[j] = woal_atox(cdata);
+ is_hex = 0;
+ } else {
+ woal_atoi(&data[j], cdata);
+ }
+ j++;
+ (*user_data_len)++;
+ k = 0;
+ memset(cdata, 0, sizeof(char) * 4);
+ } else {
+ cdata[k] = pos[i];
+ k++;
+ }
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+/**
+ * @brief Set wps & p2p ie in AP mode
+ *
+ * @param priv Pointer to priv stucture
+ * @param ie Pointer to ies data
+ * @param len Length of data
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = ie;
+ t_u32 ie_len;
+
+ ENTER();
+
+ ie_len = len - 2;
+ if (ie_len <= 0 || ie_len > MAX_IE_SIZE) {
+ PRINTM(MERROR, "IE len error: %d\n", ie_len);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE
+ "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" -- assocresp
+ IE */
+ if (*pos == '1') {
+ PRINTM(MIOCTL, "Ignore set beacon ie\n");
+ goto done;
+ } else if (*pos == '2') {
+ /* set the probe resp ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, NULL,
+ 0, pos, ie_len,
+ NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_RESP))
+ {
+ PRINTM(MERROR, "Failed to set probe resp ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (*pos == '4') {
+ /* set the assoc resp ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, NULL,
+ 0, NULL, 0, pos,
+ ie_len, NULL, 0,
+ MGMT_MASK_ASSOC_RESP))
+ {
+ PRINTM(MERROR, "Failed to set assoc resp ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_get_priv_driver_version(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ int len = 0, ret = -1;
+ char buf[MLAN_MAX_VER_STR_LEN];
+
+ ENTER();
+
+ if (!respbuf) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ /* Get version string to local buffer */
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+ len = strlen(buf);
+
+ if (len) {
+ /* Copy back the retrieved version string */
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ ret = MIN(len, (respbuflen - 1));
+ memcpy(respbuf, buf, ret);
+ } else {
+ ret = -1;
+ PRINTM(MERROR, "Get version failed!\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Hostcmd interface from application
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ t_u32 buf_len = 0;
+ HostCmd_Header cmd_header;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_MARVELL) + strlen(PRIV_CMD_HOSTCMD));
+ buf_len = *((t_u32 *) data_ptr);
+ memcpy(&cmd_header, data_ptr + sizeof(buf_len), sizeof(HostCmd_Header));
+
+ PRINTM(MINFO, "Host command len = %d\n", woal_le16_to_cpu(cmd_header.size));
+ if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ misc_cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+ /* get the whole command */
+ memcpy(misc_cfg->param.hostcmd.cmd, data_ptr + sizeof(buf_len),
+ misc_cfg->param.hostcmd.len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ memcpy(data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.cmd,
+ misc_cfg->param.hostcmd.len);
+ ret =
+ misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_HOSTCMD);
+ memcpy(data_ptr, (t_u8 *) & ret, sizeof(t_u32));
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Custom IE setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_customie(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+
+ ENTER();
+ data_ptr = respbuf + (strlen(CMD_MARVELL) + strlen(PRIV_CMD_CUSTOMIE));
+
+ custom_ie = (mlan_ds_misc_custom_ie *) data_ptr;
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ if ((custom_ie->len == 0) ||
+ (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index)))
+ ioctl_req->action = MLAN_ACT_GET;
+ else
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ custom_ie = (mlan_ds_misc_custom_ie *) data_ptr;
+ memcpy(custom_ie, &misc->param.cust_ie, sizeof(mlan_ds_misc_custom_ie));
+ ret = sizeof(mlan_ds_misc_custom_ie);
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
+ /* send a separate error code to indicate error from driver */
+ ret = EFAULT;
+ }
+ done:
+ if (ioctl_req) {
+ kfree(ioctl_req);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_bandcfg(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ unsigned int i;
+ int data[4];
+ int user_data_len = 0;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ t_u32 adhoc_chan_bandwidth = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ds_band_cfg *band_cfg = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_BANDCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_BANDCFG), data, &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (user_data_len == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from
+ MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* To support only <b/bg/bgn/n/aac/gac> */
+ infra_band = data[0];
+ for (i = 0; i < sizeof(SupportedInfraBand); i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len >= 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ if (user_data_len == 4) {
+ if (!(adhoc_band & (BAND_GN | BAND_AN))) {
+ PRINTM(MERROR,
+ "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ adhoc_chan_bandwidth = data[3];
+ /* sanity test */
+ if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW)
+ ) {
+ PRINTM(MERROR,
+ "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ }
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ radio_cfg->param.band_cfg.sec_chan_offset = adhoc_chan_bandwidth;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ band_cfg = (mlan_ds_band_cfg *) respbuf;
+
+ memcpy(band_cfg, &radio_cfg->param.band_cfg, sizeof(mlan_ds_band_cfg));
+
+ ret = sizeof(mlan_ds_band_cfg);
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_httxcfg(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_HTTXCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_HTTXCFG), data, &user_data_len);
+ }
+
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ cfg_11n->param.tx_cfg.httxcap = data[0];
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (user_data_len == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.tx_cfg.httxcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ user_data_len = 1;
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.tx_cfg.httxcap != data[0]) {
+ user_data_len = 2;
+ data[1] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n", data[0]);
+ PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
+ }
+
+ sprintf(respbuf, "0x%x", data[0]);
+ ret = strlen(respbuf) + 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get 11AC configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_get_priv_datarate(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ mlan_data_rate *data_rate = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_rate = (mlan_data_rate *) respbuf;
+
+ memcpy(data_rate, &rate->param.data_rate, sizeof(mlan_data_rate));
+
+ ret = sizeof(mlan_data_rate);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get tx rate configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_txratecfg(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[3];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ woal_tx_rate_cfg *ratecfg = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_TXRATECFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_TXRATECFG), data, &user_data_len);
+ }
+
+ if (user_data_len >= 4) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_RATE;
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+
+ if (user_data_len == 0) {
+ /* Get operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set operation */
+ req->action = MLAN_ACT_SET;
+ /* format */
+ if ((data[0] != AUTO_RATE) && (data[0] >= 3)) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == AUTO_RATE) {
+ /* auto */
+ rate->param.rate_cfg.is_rate_auto = 1;
+ } else {
+ /* fixed rate */
+ PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]);
+ if ((data[0] != AUTO_RATE) && (data[0] > MLAN_RATE_FORMAT_HT)
+ ) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if ((user_data_len >= 2) && (data[0] != AUTO_RATE)) {
+ PRINTM(MINFO, "SET: txratefg index: 0x%x\n", data[1]);
+ /* sanity check */
+ if (((data[0] == MLAN_RATE_FORMAT_LG) &&
+ (data[1] > MLAN_RATE_INDEX_OFDM7))
+ || ((data[0] == MLAN_RATE_FORMAT_HT) && (data[1] != 32) &&
+ (data[1] > 15))
+ ) {
+ PRINTM(MERROR, "Invalid index selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "SET: txratefg index: 0x%x\n", data[1]);
+ rate->param.rate_cfg.rate = data[1];
+
+ if (data[0] == MLAN_RATE_FORMAT_HT) {
+ rate->param.rate_cfg.rate = data[1] + MLAN_RATE_INDEX_MCS0;
+ }
+ }
+
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ratecfg = (woal_tx_rate_cfg *) respbuf;
+ if (rate->param.rate_cfg.is_rate_auto == MTRUE) {
+ ratecfg->rate_format = 0xFF;
+ } else {
+ /* fixed rate */
+ if (rate->param.rate_cfg.rate < MLAN_RATE_INDEX_MCS0) {
+ ratecfg->rate_format = MLAN_RATE_FORMAT_LG;
+ ratecfg->rate_index = rate->param.rate_cfg.rate;
+ } else {
+ ratecfg->rate_format = MLAN_RATE_FORMAT_HT;
+ ratecfg->rate_index =
+ rate->param.rate_cfg.rate - MLAN_RATE_INDEX_MCS0;
+ }
+ }
+
+ ret = sizeof(woal_tx_rate_cfg);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get esupplicant mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_esuppmode(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[3];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ woal_esuppmode_cfg *esupp_mode = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_ESUPPMODE))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_ESUPPMODE), data, &user_data_len);
+ }
+
+ if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+
+ if (user_data_len == 0) {
+ /* Get operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set operation */
+ req->action = MLAN_ACT_SET;
+ /* RSN mode */
+ sec->param.esupp_mode.rsn_mode = data[0];
+ /* Pairwise cipher */
+ sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF);
+ /* Group cipher */
+ sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ esupp_mode = (woal_esuppmode_cfg *) respbuf;
+ esupp_mode->rsn_mode = (t_u16) ((sec->param.esupp_mode.rsn_mode) & 0xFFFF);
+ esupp_mode->pairwise_cipher =
+ (t_u8) ((sec->param.esupp_mode.act_paircipher) & 0xFF);
+ esupp_mode->group_cipher =
+ (t_u8) ((sec->param.esupp_mode.act_groupcipher) & 0xFF);
+
+ ret = sizeof(woal_esuppmode_cfg);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get esupplicant passphrase configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_passphrase(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0, action = -1, i = 0;
+ char *begin, *end, *opt;
+ t_u16 len = 0;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *mac = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_PASSPHRASE))) {
+ PRINTM(MERROR, "No arguments provided\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Parse the buf to get the cmd_action */
+ begin = respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_PASSPHRASE);
+ end = woal_strsep(&begin, ';', '/');
+ if (end)
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ strncpy((char *) sec->param.passphrase.ssid.ssid, end, strlen(end));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid,
+ (int) sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex((t_u8 *) (sec->param.passphrase.psk.pmk.pmk), end,
+ MLAN_PMK_HEXSTR_LENGTH / 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR, "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ strncpy(sec->param.passphrase.psk.passphrase.passphrase, end,
+ sizeof(sec->param.passphrase.psk.passphrase.passphrase));
+ sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int) sec->param.passphrase.psk.passphrase.passphrase_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(respbuf, 0, respbuflen);
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(respbuf + len, "ssid:");
+ memcpy(respbuf + len, sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(respbuf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
+ mac = (t_u8 *) & sec->param.passphrase.bssid;
+ len += sprintf(respbuf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(respbuf + len, "%02x:", mac[i]);
+ len += sprintf(respbuf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(respbuf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
+ len +=
+ sprintf(respbuf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(respbuf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ len +=
+ sprintf(respbuf + len, "passphrase:%s \n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ }
+
+ ret = len;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_deauth(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ t_u8 mac[ETH_ALEN];
+
+ ENTER();
+
+ if (strlen(respbuf) > (strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEAUTH))) {
+ /* Deauth mentioned BSSID */
+ woal_mac2u8(mac,
+ respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEAUTH));
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, mac)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL))
+ ret = -EFAULT;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_bssrole(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+ t_u8 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_BSSROLE))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_BSSROLE), data, &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (user_data_len == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ if ((data[0] != MLAN_BSS_ROLE_STA &&
+ data[0] != MLAN_BSS_ROLE_UAP) ||
+ priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ if (data[0] == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ goto done;
+ }
+ action = MLAN_ACT_SET;
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv,
+ action, MOAL_IOCTL_WAIT,
+ (t_u8 *) data)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ if (user_data_len) {
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+ done:
+ memset(respbuf, 0, respbuflen);
+ respbuf[0] = (t_u8) data[0];
+ ret = 1;
+
+ error:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setuserscan(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ wlan_user_scan_cfg scan_cfg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Create the scan_cfg structure */
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+
+ /* We expect the scan_cfg structure to be passed in respbuf */
+ memcpy((char *) &scan_cfg,
+ respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_SETUSERSCAN),
+ sizeof(wlan_user_scan_cfg));
+
+ /* Call for scan */
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get deep sleep mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setgetdeepsleep(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ t_u32 data[2];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEEPSLEEP))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_DEEPSLEEP), data, &user_data_len);
+ }
+
+ if (user_data_len >= 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sprintf(respbuf, "%d %d", data[0], data[1]);
+ ret = strlen(respbuf) + 1;
+ } else {
+ if (data[0] == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (data[0] == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (user_data_len != 2)
+ data[1] = 0;
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, data[1]);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get IP address configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setgetipaddr(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, op_code = 0, data_length = 0, header = 0;
+
+ ENTER();
+
+ header = strlen(CMD_MARVELL) + strlen(PRIV_CMD_IPADDR);
+ data_length = strlen(respbuf) - header;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+
+ if (data_length < 1) { /* GET */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Make sure we have the operation argument */
+ if (data_length > 2 && respbuf[header + 1] != ';') {
+ PRINTM(MERROR, "No operation argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ respbuf[header + 1] = '\0';
+ }
+ req->action = MLAN_ACT_SET;
+
+ /* Only one IP is supported in current firmware */
+ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
+ in4_pton(&respbuf[header + 2],
+ MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
+ misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
+ misc->param.ipaddr_cfg.ip_addr_num = 1;
+ misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
+
+ if (woal_atoi(&op_code, &respbuf[header]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ipaddr_cfg.op_code = (t_u32) op_code;
+ }
+
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_IP_ADDR;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
+ misc->param.ipaddr_cfg.op_code,
+ misc->param.ipaddr_cfg.ip_addr[0][0],
+ misc->param.ipaddr_cfg.ip_addr[0][1],
+ misc->param.ipaddr_cfg.ip_addr[0][2],
+ misc->param.ipaddr_cfg.ip_addr[0][3]);
+ ret = IPADDR_MAX_BUF + 1;
+ } else {
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPS session configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setwpssession(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wps_cfg *pwps = NULL;
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_WPSSESSION))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_WPSSESSION), data, &user_data_len);
+ }
+
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+
+ if (data[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sprintf(respbuf, "OK\n") + 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get OTP user data
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_otpuserdata(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int data[1];
+ int user_data_len = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_otp_user_data *otp = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_OTPUSERDATA), data, &user_data_len);
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA;
+ misc->param.otp_user_data.user_data_length = data[0];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ otp = (mlan_ds_misc_otp_user_data *) req->pbuf;
+
+ if (req->action == MLAN_ACT_GET) {
+ ret = MIN(otp->user_data_length, data[0]);
+ memcpy(respbuf, otp->user_data, ret);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set / Get country code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_set_get_countrycode(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ // char data[COUNTRY_CODE_LEN] = {0, 0, 0};
+ int header = 0, data_length = 0; // wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_ds_misc_country_code *country_code = NULL;
+
+ ENTER();
+
+ header = strlen(CMD_MARVELL) + strlen(PRIV_CMD_COUNTRYCODE);
+ data_length = strlen(respbuf) - header;
+
+ if (data_length > COUNTRY_CODE_LEN) {
+ PRINTM(MERROR, "Invalid argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *) req->pbuf;
+ country_code = &pcfg_misc->param.country_code;
+ pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (data_length <= 1) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
+ memcpy(country_code->country_code, respbuf + header, COUNTRY_CODE_LEN);
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ ret = data_length = COUNTRY_CODE_LEN;
+ memset(respbuf + header, 0, COUNTRY_CODE_LEN);
+ memcpy(respbuf, country_code->country_code, COUNTRY_CODE_LEN);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TCP Ack enhancement configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setgettcpackenh(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+ struct list_head *link = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_TCPACKENH))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_TCPACKENH), data, &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ /* get operation */
+ respbuf[0] = priv->enable_tcp_ack_enh;
+ } else {
+ /* set operation */
+ if (data[0] == MTRUE) {
+ PRINTM(MINFO, "Enabling TCP Ack enhancement\n");
+ priv->enable_tcp_ack_enh = MTRUE;
+ } else if (data[0] == MFALSE) {
+ PRINTM(MINFO, "Disabling TCP Ack enhancement\n");
+ priv->enable_tcp_ack_enh = MFALSE;
+ /* release the tcp sessions if any */
+ while (!list_empty(&priv->tcp_sess_queue)) {
+ link = priv->tcp_sess_queue.next;
+ tcp_sess = list_entry(link, struct tcp_sess, link);
+ PRINTM(MINFO,
+ "Disable TCP ACK Enh: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ tcp_sess->src_ip_addr, tcp_sess->src_tcp_port,
+ tcp_sess->dst_ip_addr, tcp_sess->dst_tcp_port);
+ list_del(link);
+ kfree(tcp_sess);
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ respbuf[0] = priv->enable_tcp_ack_enh;
+ }
+ ret = 1;
+
+ done:
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set priv command for Android
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ android_wifi_priv_cmd priv_cmd;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ char *buf = NULL;
+ char *pdata;
+#ifdef STA_SUPPORT
+ int power_mode = 0;
+ int band = 0;
+ char *pband = NULL;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ mlan_rate_cfg_t rate;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+#endif
+ int len = 0;
+
+ ENTER();
+ if (copy_from_user(&priv_cmd, req->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf = kzalloc(priv_cmd.total_len, GFP_KERNEL);
+ if (!buf) {
+ PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (copy_from_user(buf, priv_cmd.buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name);
+
+ if (strncmp(buf, CMD_MARVELL, strlen(CMD_MARVELL)) == 0) {
+ /* This command has come from mlanutl app */
+
+ /* Check command */
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_VERSION,
+ strlen(PRIV_CMD_VERSION)) == 0) {
+ /* Get version */
+ len = woal_get_priv_driver_version(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_BANDCFG,
+ strlen(PRIV_CMD_BANDCFG)) == 0) {
+ /* Set/Get band configuration */
+ len = woal_setget_priv_bandcfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_HOSTCMD,
+ strlen(PRIV_CMD_HOSTCMD)) == 0) {
+ /* hostcmd configuration */
+ len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_HTTXCFG,
+ strlen(PRIV_CMD_HTTXCFG)) == 0) {
+ /* Set/Get HT Tx configuration */
+ len = woal_setget_priv_httxcfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_DATARATE,
+ strlen(PRIV_CMD_DATARATE)) == 0) {
+ /* Get data rate */
+ len = woal_get_priv_datarate(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_TXRATECFG,
+ strlen(PRIV_CMD_TXRATECFG)) == 0) {
+ /* Set/Get tx rate cfg */
+ len = woal_setget_priv_txratecfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_CUSTOMIE,
+ strlen(PRIV_CMD_CUSTOMIE)) == 0) {
+ /* Custom IE configuration */
+ len = woal_priv_customie(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_ESUPPMODE,
+ strlen(PRIV_CMD_ESUPPMODE)) == 0) {
+ /* Esupplicant mode configuration */
+ len = woal_setget_priv_esuppmode(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_PASSPHRASE,
+ strlen(PRIV_CMD_PASSPHRASE)) == 0) {
+ /* Esupplicant passphrase configuration */
+ len = woal_setget_priv_passphrase(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_DEAUTH,
+ strlen(PRIV_CMD_DEAUTH)) == 0) {
+ /* Deauth */
+ len = woal_priv_deauth(priv, buf, priv_cmd.total_len);
+ goto handled;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_BSSROLE,
+ strlen(PRIV_CMD_BSSROLE)) == 0) {
+ /* BSS Role */
+ len = woal_priv_bssrole(priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+#endif
+#ifdef STA_SUPPORT
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_SETUSERSCAN,
+ strlen(PRIV_CMD_SETUSERSCAN)) == 0) {
+ /* Set user scan */
+ len = woal_priv_setuserscan(priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_DEEPSLEEP,
+ strlen(PRIV_CMD_DEEPSLEEP)) == 0) {
+ /* Deep sleep */
+ len = woal_priv_setgetdeepsleep(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_IPADDR,
+ strlen(PRIV_CMD_IPADDR)) == 0) {
+ /* IP address */
+ len = woal_priv_setgetipaddr(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_WPSSESSION,
+ strlen(PRIV_CMD_WPSSESSION)) == 0) {
+ /* WPS Session */
+ len = woal_priv_setwpssession(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_OTPUSERDATA,
+ strlen(PRIV_CMD_OTPUSERDATA)) == 0) {
+ /* OTP user data */
+ len = woal_priv_otpuserdata(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_COUNTRYCODE,
+ strlen(PRIV_CMD_COUNTRYCODE)) == 0) {
+ /* OTP user data */
+ len = woal_priv_set_get_countrycode(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_TCPACKENH,
+ strlen(PRIV_CMD_TCPACKENH)) == 0) {
+ /* OTP user data */
+ len = woal_priv_setgettcpackenh(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else {
+ /* Fall through, after stripping off the custom header */
+ buf += strlen(CMD_MARVELL);
+ }
+ }
+#ifdef STA_SUPPORT
+ if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) {
+ pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_rssi_low_threshold(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT,
+ &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_info.media_connected) {
+ if (MLAN_STATUS_SUCCESS != woal_get_signal_info(priv,
+ MOAL_IOCTL_WAIT,
+ &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
+ signal.bcn_rssi_avg) + 1;
+ } else {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+ } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, MLAN_ACT_GET,
+ &rate)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate);
+ len =
+ sprintf(buf, "LinkSpeed %d\n", (int) (rate.rate * 500000 / 1000000))
+ + 1;
+ } else
+#endif
+ if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
+ len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ priv->current_addr[0], priv->current_addr[1],
+ priv->current_addr[2], priv->current_addr[3],
+ priv->current_addr[4], priv->current_addr[5]) + 1;
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_powermode(priv, &power_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
+ } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_scan_type(priv,
+ MLAN_SCAN_TYPE_ACTIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ PRINTM(MIOCTL, "Set Active Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_scan_type(priv,
+ MLAN_SCAN_TYPE_PASSIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ PRINTM(MIOCTL, "Set Passive Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
+ pdata = buf + strlen("POWERMODE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_powermode(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
+ memset(country_code, 0, sizeof(country_code));
+ memcpy(country_code, buf + strlen("COUNTRY") + 1,
+ strlen(buf) - strlen("COUNTRY") - 1);
+ PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
+ if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) {
+ PRINTM(MIOCTL, "Set Combo Scan\n");
+ if (MLAN_STATUS_SUCCESS != woal_set_combo_scan(priv, buf,
+ priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "Band %d\n", band) + 1;
+ } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
+ pband = buf + strlen("SETBAND") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "START", strlen("START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef UAP_SUPPORT
+ else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
+ if ((ret == woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START)))
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
+ if ((ret == woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)))
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) {
+ pdata = buf + strlen("AP_SET_CFG") + 1;
+ if ((ret =
+ woal_uap_set_ap_cfg(priv, pdata,
+ priv_cmd.used_len - strlen("AP_SET_CFG") - 1)))
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) == 0) {
+ // TODO Add STA list support
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_bg_scan(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
+ if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
+ if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MTRUE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MFALSE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef STA_CFG80211
+ else if (strncmp(buf, "GET_RSSI_STATUS", strlen("GET_RSSI_STATUS")) == 0) {
+ if (priv->rssi_status == MLAN_EVENT_ID_FW_BCN_RSSI_LOW)
+ len = sprintf(buf, "EVENT=BEACON_RSSI_LOW\n");
+ else if (priv->rssi_status == MLAN_EVENT_ID_FW_PRE_BCN_LOST)
+ len = sprintf(buf, "EVENT=PRE_BEACON_LOST\n");
+ else
+ len = sprintf(buf, "OK\n") + 1;
+ priv->rssi_status = 0;
+ }
+#endif
+ else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ pdata = buf + strlen("RXFILTER-ADD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == 0) {
+ pdata = buf + strlen("RXFILTER-REMOVE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
+ pdata = buf + strlen("QOSINFO") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_qos_cfg(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
+ pdata = buf + strlen("SLEEPPD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SET_AP_WPS_P2P_IE",
+ strlen("SET_AP_WPS_P2P_IE")) == 0) {
+ pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1;
+ /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE
+ "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" --
+ assocresp IE */
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ if (MLAN_STATUS_SUCCESS != woal_set_ap_wps_p2p_ie(priv, (t_u8 *) pdata,
+ priv_cmd.used_len -
+ strlen
+ ("SET_AP_WPS_P2P_IE")
+ - 1)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) {
+ memset(buf, 0x0, priv_cmd.total_len);
+ memcpy(buf, priv->current_addr, ETH_ALEN);
+ len = ETH_ALEN;
+ } else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) {
+ /* TODO Just return '\0' */
+ memset(buf, 0x0, priv_cmd.total_len);
+ *buf = 0;
+ len = 1;
+ } else {
+ PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ handled:
+ PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
+
+ if (len > 0) {
+ priv_cmd.used_len = len;
+ if (priv_cmd.used_len < priv_cmd.total_len)
+ memset(priv_cmd.buf + priv_cmd.used_len, 0,
+ priv_cmd.total_len - priv_cmd.used_len);
+ if (copy_to_user(priv_cmd.buf, buf, priv_cmd.used_len)) {
+ PRINTM(MERROR, "%s: failed to copy data to user buffer\n",
+ __FUNCTION__);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (req->ifr_data, &priv_cmd, sizeof(android_wifi_priv_cmd))) {
+ PRINTM(MERROR, "%s: failed to copy command header to user buffer\n",
+ __FUNCTION__);
+ ret = -EFAULT;
+ }
+ } else {
+ ret = len;
+ }
+
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+#ifdef WIFI_DIRECT_SUPPORT
+ case WOAL_WIFIDIRECT_HOST_CMD:
+ ret = woal_hostcmd_ioctl(dev, req);
+ break;
+#endif
+ case WOAL_CUSTOM_IE_CFG:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case WOAL_MGMT_FRAME_TX:
+ ret = woal_send_host_packet(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ case WOAL_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ default:
+#if defined(STA_WEXT)
+#ifdef STA_SUPPORT
+ ret = woal_wext_do_ioctl(dev, req, cmd);
+#else
+ ret = -EINVAL;
+#endif
+#else
+ /*
+ * FIXME Some of the IOCTLs are not supported by Marvel driver
+ * for CFG80211 and hence it is failing to turn on from UI,
+ * so returing 0(Sucess) for the time being.
+ */
+ ret = 0;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
new file mode 100644
index 000000000000..a68991694a9d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
@@ -0,0 +1,90 @@
+/** @file moal_eth_ioctl.h
+ *
+ * @brief This file contains definition for private IOCTL call.
+ *
+ * Copyright (C) 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:
+ 01/05/2012: initial version
+********************************************************/
+
+#ifndef _WOAL_ETH_PRIV_H_
+#define _WOAL_ETH_PRIV_H_
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Private command ID to Host command */
+#define WOAL_WIFIDIRECT_HOST_CMD (SIOCDEVPRIVATE + 1)
+#endif
+
+/** Private command ID to pass mgmt frame */
+#define WOAL_MGMT_FRAME_TX WOAL_MGMT_FRAME_TX_IOCTL
+
+/** Private command ID to pass custom IE list */
+#define WOAL_CUSTOM_IE_CFG (SIOCDEVPRIVATE + 13)
+
+/** Private command ID for Android ICS priv CMDs */
+#define WOAL_ANDROID_PRIV_CMD (SIOCDEVPRIVATE + 14)
+
+/** Private command ID to get BSS type */
+#define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+
+/*
+ * For android private commands, fixed value of ioctl is used.
+ * Internally commands are differentiated using strings.
+ *
+ * application needs to specify "total_len" of data for copy_from_user
+ * kernel updates "used_len" during copy_to_user
+ */
+/** Private command structure from app */
+typedef struct _android_wifi_priv_cmd
+{
+ /** Buffer pointer */
+ char *buf;
+ /** buffer updated by driver */
+ int used_len;
+ /** buffer sent by application */
+ int total_len;
+} android_wifi_priv_cmd;
+
+/** data structure for cmd txratecfg */
+typedef struct woal_priv_tx_rate_cfg
+{
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 rate_format;
+ /** Rate/MCS index (0xFF: auto) */
+ t_u32 rate_index;
+} woal_tx_rate_cfg;
+
+typedef struct woal_priv_esuppmode_cfg
+{
+ /* RSN mode */
+ t_u16 rsn_mode;
+ /* Pairwise cipher */
+ t_u8 pairwise_cipher;
+ /* Group cipher */
+ t_u8 group_cipher;
+} woal_esuppmode_cfg;
+
+mlan_status woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len);
+
+int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req);
+
+#endif /* _WOAL_ETH_PRIV_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
new file mode 100644
index 000000000000..94fe7e11669e
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
@@ -0,0 +1,4463 @@
+/** @file moal_ioctl.c
+ *
+ * @brief This file contains ioctl function to MLAN
+ *
+ * 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 "moal_main.h"
+#include "moal_eth_ioctl.h"
+#include "moal_sdio.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/* CAC Measure report default time 60 seconds */
+#define MEAS_REPORT_TIME 60*HZ
+#define MRVL_TLV_HEADER_SIZE 4
+/* Marvell Channel config TLV ID */
+#define MRVL_CHANNELCONFIG_TLV_ID (0x0100 + 0x2a) // 0x012a
+
+typedef struct _hostcmd_header
+{
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command action */
+ t_u16 action;
+} hostcmd_header, *phostcmd_header;
+
+#ifdef STA_SUPPORT
+/** Region code mapping */
+typedef struct _region_code_mapping_t
+{
+ /** 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 */
+ {"CN ", 0x50}, /* China */
+ {"JP ", 0xFF}, /* Japan special */
+};
+#endif
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef STA_SUPPORT
+/**
+ * @brief This function converts region string to region code
+ *
+ * @param region_string Region string
+ *
+ * @return Region code
+ */
+static t_u8
+region_string_2_region_code(char *region_string)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+ for (i = 0; i < size; i++) {
+ if (!memcmp(region_string,
+ region_code_mapping[i].region, strlen(region_string))) {
+ LEAVE();
+ return (region_code_mapping[i].code);
+ }
+ }
+ /* Default is US */
+ LEAVE();
+ return (region_code_mapping[0].code);
+}
+#endif
+
+/**
+ * @brief Copy multicast table
+ *
+ * @param mlist A pointer to mlan_multicast_list structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return Number of multicast addresses
+ */
+static inline int
+woal_copy_mcast_addr(mlan_multicast_list * mlist, struct net_device *dev)
+{
+ int i = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mcptr = dev->mc_list;
+#else
+ struct netdev_hw_addr *mcptr = NULL;
+#endif /* < 2.6.35 */
+
+ ENTER();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ for (i = 0; i < dev->mc_count && mcptr; i++) {
+ memcpy(&mlist->mac_list[i], mcptr->dmi_addr, ETH_ALEN);
+ mcptr = mcptr->next;
+ }
+#else
+ netdev_for_each_mc_addr(mcptr, dev)
+ memcpy(&mlist->mac_list[i++], mcptr->addr, ETH_ALEN);
+#endif /* < 2.6.35 */
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Fill in wait queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait A pointer to wait_queue structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+static inline void
+woal_fill_wait_queue(moal_private * priv, wait_queue * wait, t_u8 wait_option)
+{
+ ENTER();
+ wait->start_time = jiffies;
+ wait->condition = MFALSE;
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ wait->wait = &priv->ioctl_wait_q;
+ break;
+ case MOAL_CMD_WAIT:
+ wait->wait = &priv->cmd_wait_q;
+ break;
+ case MOAL_PROC_WAIT:
+ wait->wait = &priv->proc_wait_q;
+ break;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ case MOAL_WSTATS_WAIT:
+ if (IS_STA_OR_UAP_WEXT(cfg80211_wext))
+ wait->wait = &priv->w_stats_wait_q;
+ break;
+#endif
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Wait mlan ioctl complete
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+static inline void
+woal_wait_ioctl_complete(moal_private * priv, mlan_ioctl_req * req,
+ t_u8 wait_option)
+{
+ mlan_status status;
+ wait_queue *wait = (wait_queue *) req->reserved_1;
+
+ ENTER();
+
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ wait_event_interruptible(priv->ioctl_wait_q, wait->condition);
+ break;
+ case MOAL_CMD_WAIT:
+ wait_event_interruptible(priv->cmd_wait_q, wait->condition);
+ break;
+ case MOAL_PROC_WAIT:
+ wait_event_interruptible(priv->proc_wait_q, wait->condition);
+ break;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ case MOAL_WSTATS_WAIT:
+ if (IS_STA_OR_UAP_WEXT(cfg80211_wext))
+ wait_event_interruptible(priv->w_stats_wait_q, wait->condition);
+ break;
+#endif
+ }
+ if (wait->condition == MFALSE) {
+ req->action = MLAN_ACT_CANCEL;
+ status = mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ PRINTM(MIOCTL,
+ "IOCTL cancel: id=0x%x, sub_id=0x%x, wait_option=%d, action=%d, status=%d\n",
+ req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action, status);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief CAC period block cmd handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ *
+ * @return MTRUE/MFALSE
+ */
+static inline t_bool
+woal_cac_period_block_cmd(moal_private * priv, pmlan_ioctl_req req)
+{
+ mlan_status ret = MFALSE;
+ t_u32 sub_command;
+
+ ENTER();
+ if (req == NULL || req->pbuf == NULL) {
+ goto done;
+ }
+
+ sub_command = *(t_u32 *) req->pbuf;
+
+ switch (req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ if (sub_command == MLAN_OID_SCAN_NORMAL ||
+ sub_command == MLAN_OID_SCAN_SPECIFIC_SSID ||
+ sub_command == MLAN_OID_SCAN_USER_CONFIG) {
+ ret = MTRUE;
+ }
+ break;
+ case MLAN_IOCTL_BSS:
+ if (sub_command == MLAN_OID_BSS_STOP ||
+#ifdef UAP_SUPPORT
+ sub_command == MLAN_OID_UAP_BSS_CONFIG ||
+#endif
+ sub_command == MLAN_OID_BSS_CHANNEL
+ /* sub_command == MLAN_OID_BSS_ROLE */ ) {
+ ret = MTRUE;
+ }
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ if (sub_command == MLAN_OID_BAND_CFG) {
+ ret = MTRUE;
+ }
+ break;
+#if defined(UAP_SUPPORT)
+ case MLAN_IOCTL_SNMP_MIB:
+ if (sub_command == MLAN_OID_SNMP_MIB_DOT11D ||
+ sub_command == MLAN_OID_SNMP_MIB_DOT11H) {
+ ret = MTRUE;
+ }
+ break;
+#endif
+ case MLAN_IOCTL_11D_CFG:
+#ifdef STA_SUPPORT
+ if (sub_command == MLAN_OID_11D_CFG_ENABLE) {
+ ret = MTRUE;
+ }
+#endif
+ if (sub_command == MLAN_OID_11D_DOMAIN_INFO) {
+ ret = MTRUE;
+ }
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ if (sub_command == MLAN_OID_MISC_REGION) {
+ ret = MTRUE;
+ }
+ if (sub_command == MLAN_OID_MISC_HOST_CMD) {
+ phostcmd_header phostcmd;
+ t_u8 *ptlv_buf;
+ t_u16 tag, length;
+
+ phostcmd =
+ (phostcmd_header) ((pmlan_ds_misc_cfg) req->pbuf)->param.
+ hostcmd.cmd;
+ ptlv_buf = (t_u8 *) phostcmd + sizeof(hostcmd_header);
+ if (phostcmd->action == MLAN_ACT_SET) {
+ while (ptlv_buf < (t_u8 *) phostcmd + phostcmd->size) {
+ tag = *(t_u16 *) ptlv_buf;
+ length = *(t_u16 *) (ptlv_buf + 2);
+ /* Check Blocking TLV here, should add more... */
+ if (tag == MRVL_CHANNELCONFIG_TLV_ID) {
+ ret = MTRUE;
+ break;
+ }
+ ptlv_buf += (length + MRVL_TLV_HEADER_SIZE);
+ }
+ }
+ }
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ /* Prevent execute more than once */
+ if (sub_command == MLAN_OID_11H_CHANNEL_CHECK) {
+ ret = MTRUE;
+ }
+ break;
+ default:
+ ret = MFALSE;
+ break;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Send ioctl request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option)
+{
+ wait_queue *wait;
+ mlan_status status;
+
+ ENTER();
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ PRINTM(MERROR,
+ "IOCTL is not allowed while the device is not present\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#if defined(SDIO_SUSPEND_RESUME)
+ if (priv->phandle->is_suspended == MTRUE) {
+ PRINTM(MERROR, "IOCTL is not allowed while suspended\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+
+ /* For MLAN_OID_MISC_HOST_CMD, action is 0, "action set" is checked later */
+ if ((req->action == MLAN_ACT_SET || req->action == 0) &&
+ priv->phandle->cac_period == MTRUE) {
+ t_u32 sub_command;
+ /* CAC checking period left to complete jiffies */
+ unsigned long cac_left_jiffies;
+
+ sub_command = *(t_u32 *) req->pbuf;
+
+ /* cac_left_jiffies will be negative if and only if * event
+ MLAN_EVENT_ID_DRV_MEAS_REPORT recieved from FW * after CAC measure
+ period ends, * usually this could be considered as a FW bug */
+ cac_left_jiffies = MEAS_REPORT_TIME -
+ (jiffies - priv->phandle->meas_start_jiffies);
+#ifdef DFS_TESTING_SUPPORT
+ if (priv->phandle->cac_period_jiffies) {
+ cac_left_jiffies = priv->phandle->cac_period_jiffies -
+ (jiffies - priv->phandle->meas_start_jiffies);
+ }
+#endif
+ if (cac_left_jiffies < 0) {
+ /* Avoid driver hang in FW died during CAC measure period */
+ priv->phandle->cac_period = MFALSE;
+ PRINTM(MERROR,
+ "CAC measure period spends longer than scheduled time "
+ "or meas done event never received\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Check BSS START first */
+ if (sub_command == MLAN_OID_BSS_START) {
+ mlan_ds_bss *bss;
+ bss = (mlan_ds_bss *) req->pbuf;
+ /*
+ * Bss delay start after channel report received,
+ * not block the driver by delay executing. This is
+ * because a BSS_START cmd is always executed right
+ * after channel check issued.
+ */
+ if (priv->phandle->delay_bss_start == MFALSE) {
+ PRINTM(MMSG, "Received BSS Start command during CAC period, "
+ "delay executing %ld seconds\n", cac_left_jiffies / HZ);
+ priv->phandle->delay_bss_start = MTRUE;
+ memcpy(&priv->phandle->delay_ssid_bssid,
+ &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid));
+ /* TODO: return success to allow the half below of routines of
+ which calling BSS start to execute */
+ status = MLAN_STATUS_SUCCESS;
+ goto done;
+ } else {
+ /* TODO: not blocking it, just return failure */
+ PRINTM(MMSG, "Only one BSS Start command allowed for delay "
+ "executing!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (woal_cac_period_block_cmd(priv, req)) {
+ priv->phandle->meas_wait_q_woken = MFALSE;
+ PRINTM(MMSG, "CAC check is on going... Blocking Command"
+ " %ld seconds\n", cac_left_jiffies / HZ);
+ /* blocking timeout set to 1.5 * CAC checking period left time */
+ wait_event_interruptible_timeout(priv->phandle->meas_wait_q,
+ priv->phandle->meas_wait_q_woken,
+ cac_left_jiffies * 3 / 2);
+ }
+ } else if (priv->phandle->cac_period) {
+ PRINTM(MINFO, "Operation during CAC check period.\n");
+ }
+ wait = (wait_queue *) req->reserved_1;
+ req->bss_index = priv->bss_index;
+ if (wait_option)
+ woal_fill_wait_queue(priv, wait, wait_option);
+ else
+ req->reserved_1 = 0;
+
+ /* Call MLAN ioctl handle */
+ status = mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ PRINTM(MIOCTL,
+ "IOCTL pending: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d\n",
+ req, req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action);
+ atomic_inc(&priv->phandle->ioctl_pending);
+ /* Status pending, wake up main process */
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* Wait for completion */
+ if (wait_option) {
+ woal_wait_ioctl_complete(priv, req, wait_option);
+ status = wait->status;
+ }
+ break;
+ case MLAN_STATUS_SUCCESS:
+ case MLAN_STATUS_FAILURE:
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MIOCTL,
+ "IOCTL: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d status=%d\n",
+ req, req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action, status);
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send set MAC address request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_request_set_mac_address(moal_private * priv)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
+ memcpy(&bss->param.mac_addr, priv->current_addr,
+ sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_CMD_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy)
+ memcpy(priv->wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN);
+#endif
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ } else {
+ PRINTM(MERROR, "set mac address failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send multicast list request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void
+woal_request_set_multicast_list(moal_private * priv, struct net_device *dev)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ int mc_count = dev->mc_count;
+#else
+ int mc_count = netdev_mc_count(dev);
+#endif
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ PRINTM(MERROR, "%s:Fail to allocate ioctl req buffer\n", __FUNCTION__);
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MULTICAST_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (dev->flags & IFF_PROMISC) {
+ bss->param.multicast_list.mode = MLAN_PROMISC_MODE;
+ } else if (dev->flags & IFF_ALLMULTI ||
+ mc_count > MLAN_MAX_MULTICAST_LIST_SIZE) {
+ bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE;
+ } else {
+ bss->param.multicast_list.mode = MLAN_MULTICAST_MODE;
+ if (mc_count)
+ bss->param.multicast_list.num_multicast_addr =
+ woal_copy_mcast_addr(&bss->param.multicast_list, dev);
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_NO_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send deauth command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param mac MAC address to deauthenticate
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ if (mac)
+ memcpy((t_u8 *) & bss->param.bssid, mac, sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+#ifdef REASSOCIATION
+ priv->reassoc_required = MFALSE;
+#endif /* REASSOCIATION */
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send bss_start command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A point to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_bss_start(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Stop the O.S. TX queue if needed */
+ woal_stop_queue(priv->netdev);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_START;
+ if (ssid_bssid)
+ memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get BSS info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param bss_info A pointer to mlan_bss_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_bss_info(moal_private * priv, t_u8 wait_option,
+ mlan_bss_info * bss_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_BSS_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (bss_info) {
+ memcpy(bss_info, &info->param.bss_info, sizeof(mlan_bss_info));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set/Get retry count
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value Retry value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_retry(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RETRY_COUNT;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_TX_RETRY_MIN || *value > MLAN_TX_RETRY_MAX) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.retry_count = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = mib->param.retry_count;
+ }
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy retry count
+ should be updated as well */
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) {
+ priv->wdev->wiphy->retry_long = (t_u8) * value;
+ priv->wdev->wiphy->retry_short = (t_u8) * value;
+ }
+#endif
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RTS threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value RTS threshold value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_rts(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RTS_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_RTS_MIN_VALUE || *value > MLAN_RTS_MAX_VALUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.rts_threshold = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = mib->param.rts_threshold;
+ }
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy RTS threshold
+ should be updated as well */
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET))
+ priv->wdev->wiphy->rts_threshold = *value;
+#endif
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Fragment threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value Fragment threshold value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_frag(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_FRAG_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_FRAG_MIN_VALUE || *value > MLAN_FRAG_MAX_VALUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.frag_threshold = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = mib->param.frag_threshold;
+ }
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy fragment
+ threshold should be updated as well */
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET))
+ priv->wdev->wiphy->frag_threshold = *value;
+#endif
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param ie Information element
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie, int *ie_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if ((action == MLAN_ACT_GET) && (ie == NULL || ie_len == NULL)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_SET && *ie_len > MAX_IE_SIZE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+
+ if (action == MLAN_ACT_SET) {
+ misc->param.gen_ie.len = *ie_len;
+ if (*ie_len)
+ memcpy(misc->param.gen_ie.ie_data, ie, *ie_len);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ *ie_len = misc->param.gen_ie.len;
+ if (*ie_len)
+ memcpy(ie, misc->param.gen_ie.ie_data, *ie_len);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param power_cfg A pinter to mlan_power_cfg_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_tx_power(moal_private * priv,
+ t_u32 action, mlan_power_cfg_t * power_cfg)
+{
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET && power_cfg)
+ memcpy(&pcfg->param.power_cfg, power_cfg, sizeof(mlan_power_cfg_t));
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+
+ if (ret == MLAN_STATUS_SUCCESS && power_cfg)
+ memcpy(power_cfg, &pcfg->param.power_cfg, sizeof(mlan_power_cfg_t));
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IEEE power management
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param disabled A pointer to disabled flag
+ * @param power_type IEEE power type
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_power_mgmt(moal_private * priv,
+ t_u32 action, int *disabled, int power_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "PS_MODE set power disabled=%d power type=%#x\n",
+ *disabled, power_type);
+ if (*disabled)
+ pm_cfg->param.ps_mode = 0;
+ else {
+ /* Check not support case only (vwrq->disabled == FALSE) */
+ if ((power_type & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ PRINTM(MERROR, "Setting power timeout is not supported\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else if ((power_type & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+ PRINTM(MERROR, "Setting power period is not supported\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg->param.ps_mode = 1;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *disabled = pm_cfg->param.ps_mode;
+
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save
+ mode should be updated */
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) {
+ if (*disabled)
+ priv->wdev->ps = MFALSE;
+ else
+ priv->wdev->ps = MTRUE;
+ }
+#endif
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param region A pointer to region string
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+woal_set_region_code(moal_private * priv, char *region)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region_string_2_region_code(region);
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param datarate A pointer to mlan_rate_cfg_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_data_rate(moal_private * priv,
+ t_u8 action, mlan_rate_cfg_t * datarate)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = action;
+
+ if (datarate && (action == MLAN_ACT_SET))
+ memcpy(&rate->param.rate_cfg, datarate, sizeof(mlan_rate_cfg_t));
+
+ if (MLAN_STATUS_SUCCESS == woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ if (datarate && (action == MLAN_ACT_GET))
+ memcpy(datarate, &rate->param.rate_cfg, sizeof(mlan_rate_cfg_t));
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Send get FW info request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param fw_info FW information
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_request_get_fw_info(moal_private * priv, t_u8 wait_option,
+ mlan_fw_info * fw_info)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info;
+ mlan_status status;
+ ENTER();
+ memset(priv->current_addr, 0xff, ETH_ALEN);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ info->sub_command = MLAN_OID_GET_FW_INFO;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->phandle->fw_release_number = info->param.fw_info.fw_ver;
+ if (priv->current_addr[0] == 0xff)
+ memcpy(priv->current_addr, &info->param.fw_info.mac_addr,
+ sizeof(mlan_802_11_mac_addr));
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy)
+ memcpy(priv->wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN);
+#endif
+ if (fw_info)
+ memcpy(fw_info, &info->param.fw_info, sizeof(mlan_fw_info));
+ DBG_HEXDUMP(MCMD_D, "mac", priv->current_addr, 6);
+ } else
+ PRINTM(MERROR, "get fw info failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#ifdef PROC_DEBUG
+/**
+ * @brief Get debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (debug_info) {
+ memcpy(debug_info, &info->param.debug_info,
+ sizeof(mlan_debug_info));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!debug_info) {
+ ret = -EINVAL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ memcpy(&info->param.debug_info, debug_info, sizeof(mlan_debug_info));
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+#endif /* PROC_DEBUG */
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief host command ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_host_command(moal_private * priv, struct iwreq *wrq)
+{
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (wrq->u.data.pointer == NULL) {
+ PRINTM(MERROR, "hostcmd IOCTL corrupt data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user
+ (&cmd_header, wrq->u.data.pointer, sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "copy from user failed: Host command header\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ PRINTM(MINFO, "Host command len = %u\n", misc->param.hostcmd.len);
+
+ if (!misc->param.hostcmd.len ||
+ misc->param.hostcmd.len > MLAN_SIZE_OF_CMD_BUFFER) {
+ PRINTM(MERROR, "Invalid data buffer length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.hostcmd.cmd, wrq->u.data.pointer,
+ woal_le16_to_cpu(cmd_header.size))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = misc->param.hostcmd.len;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT)
+/**
+ * @brief host command ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+/********* format of ifr_data *************/
+/* buf_len + Hostcmd_body */
+/* buf_len: 4 bytes */
+/* the length of the buf which */
+/* can be used to return data */
+/* to application */
+/* Hostcmd_body */
+/*******************************************/
+int
+woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 buf_len = 0;
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hostcmd_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user
+ (&cmd_header, req->ifr_data + sizeof(buf_len),
+ sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MINFO, "Host command len = %d\n", woal_le16_to_cpu(cmd_header.size));
+
+ if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.hostcmd.cmd, req->ifr_data + sizeof(buf_len),
+ misc->param.hostcmd.len)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (misc->param.hostcmd.len > buf_len) {
+ PRINTM(MERROR, "buf_len is too small, resp_len=%d, buf_len=%d\n",
+ (int) misc->param.hostcmd.len, (int) buf_len);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (req->ifr_data + sizeof(buf_len), (t_u8 *) misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief CUSTOM_IE ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_custom_ie_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(custom_ie, 0, sizeof(mlan_ds_misc_custom_ie));
+
+ if (copy_from_user
+ (custom_ie, req->ifr_data, sizeof(mlan_ds_misc_custom_ie))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ if ((custom_ie->len == 0) ||
+ (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index)))
+ ioctl_req->action = MLAN_ACT_GET;
+ else
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (req->ifr_data, &misc->param.cust_ie,
+ sizeof(mlan_ds_misc_custom_ie))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
+ /* send a separate error code to indicate error from driver */
+ ret = EFAULT;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ if (custom_ie)
+ kfree(custom_ie);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send raw data packet ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_send_host_packet(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 packet_len = 0;
+ int ret = 0;
+ pmlan_buffer pmbuf = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_send_host_packet() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&packet_len, req->ifr_data, sizeof(packet_len))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+#define PACKET_HEADER_LEN 8
+ pmbuf =
+ woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + packet_len +
+ PACKET_HEADER_LEN);
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+
+ /* get whole packet and header */
+ if (copy_from_user
+ (pmbuf->pbuf + pmbuf->data_offset, req->ifr_data + sizeof(packet_len),
+ PACKET_HEADER_LEN + packet_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = PACKET_HEADER_LEN + packet_len;
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#if defined(UAP_WEXT)
+/**
+ * @brief Set/Get CUSTOM_IE ioctl handler
+ *
+ * @param mask Mask to set or clear from caller
+ * @param ie IE buffer to set for beacon
+ * @param ie_len Length of the IE
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie, int ie_len)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *misc_ie = NULL;
+ int ret = 0;
+ custom_ie *pcust_bcn_ie = NULL;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+ misc_ie = &misc->param.cust_ie;
+
+#ifndef TLV_TYPE_MGMT_IE
+#define TLV_TYPE_MGMT_IE (0x169)
+#endif
+ misc_ie->type = TLV_TYPE_MGMT_IE;
+ misc_ie->len = (sizeof(custom_ie) - MAX_IE_SIZE) + ie_len;
+ pcust_bcn_ie = misc_ie->ie_data_list;
+ pcust_bcn_ie->ie_index = 0xffff;
+ pcust_bcn_ie->mgmt_subtype_mask = mask;
+ pcust_bcn_ie->ie_length = ie_len;
+ memcpy(pcust_bcn_ie->ie_buffer, ie, ie_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif /* defined(HOST_TXRX_MGMT_FRAME) && defined(UAP_WEXT) */
+
+/**
+ * @brief ioctl function get BSS type
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_bss_type(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int bss_type;
+
+ ENTER();
+
+ bss_type = (int) priv->bss_type;
+ if (copy_to_user(req->ifr_data, &bss_type, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief Swithces BSS role of WFD interface
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param bss_role A pointer to bss role
+ *
+ * @return 0 --success, otherwise fail
+ */
+mlan_status
+woal_bss_role_cfg(moal_private * priv, t_u8 action,
+ t_u8 wait_option, t_u8 * bss_role)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ struct net_device *dev = priv->netdev;
+
+ ENTER();
+
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MWARN, "Command is not allowed for this interface\n");
+ ret = -EPERM;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_ROLE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+ if (action == MLAN_ACT_SET) {
+ bss->param.bss_role = *bss_role;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ *bss_role = bss->param.bss_role;
+ } else {
+ /* Update moal_private */
+ priv->bss_role = *bss_role;
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_type = MLAN_BSS_TYPE_UAP;
+
+ if (*bss_role == MLAN_BSS_ROLE_UAP) {
+ /* Switch: STA -> uAP */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+#ifdef WIRELESS_EXT
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_uap_handler_def;
+#endif /* WIRELESS_EXT */
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ }
+#endif /* UAP_WEXT */
+ } else if (*bss_role == MLAN_BSS_ROLE_STA) {
+ /* Switch: uAP -> STA */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#ifdef WIRELESS_EXT
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_handler_def;
+#endif
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ }
+#endif /* STA_WEXT */
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int bss_role = 0;
+ t_u8 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bss_role != MLAN_BSS_ROLE_STA &&
+ bss_role != MLAN_BSS_ROLE_UAP) ||
+ (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT)) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (bss_role == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ action = MLAN_ACT_SET;
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv,
+ action, MOAL_IOCTL_WAIT,
+ (t_u8 *) & bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/**
+ * @brief Get Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param hscfg A pointer to mlan_ds_hs_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_hs_params(moal_private * priv, t_u16 action, t_u8 wait_option,
+ mlan_ds_hs_cfg * hscfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ memcpy(&pmcfg->param.hs_cfg, hscfg, sizeof(mlan_ds_hs_cfg));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (hscfg && action == MLAN_ACT_GET) {
+ memcpy(hscfg, &pmcfg->param.hs_cfg, sizeof(mlan_ds_hs_cfg));
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING,
+ * or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cancel_hs(moal_private * priv, t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_hs_cfg hscfg;
+
+ ENTER();
+
+ /* Cancel Host Sleep */
+ hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ hscfg.is_invoke_hostcmd = MTRUE;
+ ret = woal_set_get_hs_params(priv, MLAN_ACT_SET, wait_option, &hscfg);
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO_SUSPEND_RESUME)
+/** @brief This function enables the host sleep
+ *
+ * @param priv A Pointer to the moal_private structure
+ * @return MTRUE or MFALSE
+ */
+int
+woal_enable_hs(moal_private * priv)
+{
+ mlan_ds_hs_cfg hscfg;
+ moal_handle *handle = NULL;
+ int hs_actived = MFALSE;
+ int timeout = 0;
+#ifdef SDIO_SUSPEND_RESUME
+ mlan_ds_ps_info pm_info;
+#endif
+
+ ENTER();
+
+ if (priv == NULL) {
+ PRINTM(MERROR, "Invalid priv\n");
+ goto done;
+ }
+ handle = priv->phandle;
+ if (handle->hs_activated == MTRUE) {
+ PRINTM(MIOCTL, "HS Already actived\n");
+ hs_actived = MTRUE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ woal_reconfig_bgscan(priv->phandle);
+#endif
+ /* Enable Host Sleep */
+ handle->hs_activate_wait_q_woken = MFALSE;
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ hscfg.is_invoke_hostcmd = MTRUE;
+ if (woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_NO_WAIT, &hscfg) ==
+ MLAN_STATUS_FAILURE) {
+ PRINTM(MIOCTL, "IOCTL request HS enable failed\n");
+ goto done;
+ }
+ timeout = wait_event_interruptible_timeout(handle->hs_activate_wait_q,
+ handle->hs_activate_wait_q_woken,
+ HS_ACTIVE_TIMEOUT);
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ if ((handle->hs_activated == MTRUE) || (handle->is_suspended == MTRUE)) {
+ PRINTM(MCMND, "suspend success! force=%u skip=%u\n",
+ handle->hs_force_count, handle->hs_skip_count);
+ hs_actived = MTRUE;
+ }
+#ifdef SDIO_SUSPEND_RESUME
+ else {
+ handle->suspend_fail = MTRUE;
+ woal_get_pm_info(priv, &pm_info);
+ if (pm_info.is_suspend_allowed == MTRUE) {
+#ifdef MMC_PM_FUNC_SUSPENDED
+ woal_wlan_is_suspended(priv->phandle);
+#endif
+ handle->hs_force_count++;
+ PRINTM(MCMND, "suspend allowed! force=%u skip=%u\n",
+ handle->hs_force_count, handle->hs_skip_count);
+ hs_actived = MTRUE;
+ }
+ }
+#endif /* SDIO_SUSPEND_RESUME */
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (hs_actived != MTRUE) {
+ handle->hs_skip_count++;
+#ifdef SDIO_SUSPEND_RESUME
+ PRINTM(MCMND, "suspend skipped! timeout=%d allow=%d force=%u skip=%u\n",
+ timeout, (int) pm_info.is_suspend_allowed,
+ handle->hs_force_count, handle->hs_skip_count);
+#else
+ PRINTM(MCMND, "suspend skipped! timeout=%d skip=%u\n",
+ timeout, handle->hs_skip_count);
+#endif
+ woal_cancel_hs(priv, MOAL_NO_WAIT);
+ }
+ done:
+ LEAVE();
+ return hs_actived;
+}
+#endif
+
+/**
+ * @brief This function send soft_reset command to firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success, otherwise failure code
+ */
+mlan_status
+woal_request_soft_reset(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_SOFT_RESET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ ret =
+ woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), req,
+ MOAL_PROC_WAIT);
+ }
+
+ handle->surprise_removed = MTRUE;
+ woal_sched_timeout(5);
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wapi enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WAPI_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wapi_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get version
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void
+woal_get_version(moal_handle * handle, char *version, int max_len)
+{
+ union
+ {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+ char fw_ver[32];
+
+ ENTER();
+
+ ver.l = handle->fw_release_number;
+ snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u",
+ ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+ snprintf(version, max_len, driver_version, fw_ver);
+
+ LEAVE();
+}
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_driver_version(moal_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *) req;
+ int len;
+ char buf[MLAN_MAX_VER_STR_LEN];
+ ENTER();
+
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+
+ len = strlen(buf);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ wrq->u.data.length = len;
+ }
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get extended driver version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ireq A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_driver_verext(moal_private * priv, struct ifreq *ireq)
+{
+ struct iwreq *wrq = (struct iwreq *) ireq;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ if (!wrq->u.data.flags) {
+ info->param.ver_ext.version_str_sel =
+ *((int *) (wrq->u.name + SUBCMD_OFFSET));
+ } else {
+ if (copy_from_user
+ (&info->param.ver_ext.version_str_sel, wrq->u.data.pointer,
+ sizeof(info->param.ver_ext.version_str_sel))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (((t_s32) (info->param.ver_ext.version_str_sel)) < 0) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, info->param.ver_ext.version_str,
+ strlen(info->param.ver_ext.version_str))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = strlen(info->param.ver_ext.version_str);
+ }
+
+ PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
+ info->param.ver_ext.version_str);
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set driver debug bit masks to mlan in order to enhance performance
+ *
+ * @param priv A pointer to moal_private structure
+ * @param drvdbg Driver debug level
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_drvdbg(moal_private * priv, t_u32 drvdbg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_DRVDBG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc->param.drvdbg = drvdbg;
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Mgmt frame forward registration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param pmgmt_subtype_mask A Pointer to mgmt frame subtype mask
+ * @param wait_option wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action,
+ t_u32 * pmgmt_subtype_mask, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ misc->param.mgmt_subtype_mask = *pmgmt_subtype_mask;
+ if (req->action == MLAN_ACT_SET)
+ memcpy(&misc->param.mgmt_subtype_mask,
+ pmgmt_subtype_mask, sizeof(misc->param.mgmt_subtype_mask));
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+ if (req->action == MLAN_ACT_GET)
+ memcpy(pmgmt_subtype_mask, &misc->param.mgmt_subtype_mask,
+ sizeof(misc->param.mgmt_subtype_mask));
+
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param tx_bf_cfg A pointer to tx_bf_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action,
+ mlan_ds_11n_tx_bf_cfg * tx_bf_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+
+ ENTER();
+
+ /* Sanity test */
+ if (tx_bf_cfg == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CFG;
+
+ req->action = action;
+ memcpy(&bf_cfg->param.tx_bf, tx_bf_cfg, sizeof(mlan_ds_11n_tx_bf_cfg));
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET)
+ memcpy(tx_bf_cfg, &bf_cfg->param.tx_bf, sizeof(mlan_ds_11n_tx_bf_cfg));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle ioctl resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param req Pointer to mlan_ioctl_req structure
+ *
+ * @return N/A
+ */
+void
+woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req)
+{
+ ENTER();
+
+ if (priv == NULL) {
+ LEAVE();
+ return;
+ }
+ switch (req->req_id) {
+ case MLAN_IOCTL_GET_INFO:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ woal_ioctl_get_info_resp(priv, (mlan_ds_get_info *) req->pbuf);
+#endif
+#endif
+#ifdef UAP_WEXT
+#ifdef UAP_SUPPORT
+ if (IS_UAP_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ woal_ioctl_get_uap_info_resp(priv, (mlan_ds_get_info *) req->pbuf);
+#endif
+#endif
+ break;
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ case MLAN_IOCTL_BSS:
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ woal_ioctl_get_bss_resp(priv, (mlan_ds_bss *) req->pbuf);
+ break;
+#endif
+#endif
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get PM info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pm_info A pointer to mlan_ds_ps_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Fail to alloc mlan_ds_pm_cfg buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_INFO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_CMD_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (pm_info) {
+ memcpy(pm_info, &pmcfg->param.ps_info, sizeof(mlan_ds_ps_info));
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param data Pointer to return deep_sleep setting
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_deep_sleep(moal_private * priv, t_u32 * data)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ *data = pm->param.auto_deep_sleep.auto_ds;
+ *(data + 1) = pm->param.auto_deep_sleep.idletime;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wait_option wait option
+ * @param bdeep_sleep TRUE--enalbe deepsleep, FALSE--disable deepsleep
+ * @param idletime Idle time for optimized PS API
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, BOOLEAN bdeep_sleep,
+ t_u16 idletime)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_SET;
+ if (bdeep_sleep == MTRUE) {
+ PRINTM(MIOCTL, "Deep Sleep: sleep\n");
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ if (idletime) {
+ pm->param.auto_deep_sleep.idletime = idletime;
+ }
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MIOCTL, "%lu : Deep Sleep: wakeup\n", jiffies);
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel CAC period block
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_cancel_cac_block(moal_private * priv)
+{
+ ENTER();
+ /* if during CAC period, wake up wait queue */
+ if (priv->phandle->cac_period == MTRUE) {
+ priv->phandle->cac_period = MFALSE;
+ priv->phandle->meas_start_jiffies = 0;
+ if (priv->phandle->delay_bss_start == MTRUE) {
+ priv->phandle->delay_bss_start = MFALSE;
+ }
+ if (priv->phandle->meas_wait_q_woken == MFALSE) {
+ priv->phandle->meas_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->meas_wait_q);
+ }
+ }
+ LEAVE();
+}
+
+/** MEAS report timeout value in seconds */
+
+/**
+ * @brief Issue MLAN_OID_11H_CHANNEL_CHECK ioctl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_11h_channel_check_ioctl(moal_private * priv)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_SET;
+ /* Send Channel Check command and wait until the report is ready */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* set flag from here */
+ priv->phandle->cac_period = MTRUE;
+ priv->phandle->meas_start_jiffies = jiffies;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/**
+ * @brief set/get wifi direct mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action set or get
+ * @param mode A pointer to wifi direct mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, t_u16 * mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_WIFI_DIRECT_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ bss->param.wfd_mode = *mode;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ *mode = bss->param.wfd_mode;
+ PRINTM(MIOCTL, "ACT=%d, wifi_direct_mode=%d\n", action, *mode);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set remain channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param pchan A pointer to mlan_ds_remain_chan structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option,
+ mlan_ds_remain_chan * pchan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_REMAIN_CHAN_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ req->action = MLAN_ACT_SET;
+ memcpy(&radio_cfg->param.remain_chan, pchan, sizeof(mlan_ds_remain_chan));
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ memcpy(pchan, &radio_cfg->param.remain_chan,
+ sizeof(mlan_ds_remain_chan));
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Get RSSI info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param signal A pointer tp mlan_ds_get_signal structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_signal_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_signal * signal)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_SIGNAL;
+ info->param.signal.selector = ALL_RSSI_INFO_MASK;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (signal)
+ memcpy(signal, &info->param.signal, sizeof(mlan_ds_get_signal));
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg;
+ }
+#endif
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get scan table
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_scan_table(moal_private * priv, t_u8 wait_option,
+ mlan_scan_resp * scan_resp)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+ memcpy((void *) &scan->param.scan_resp, (void *) scan_resp,
+ sizeof(mlan_scan_resp));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (scan_resp) {
+ memcpy(scan_resp, &scan->param.scan_resp, sizeof(mlan_scan_resp));
+ }
+ }
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Request a scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param req_ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_scan(moal_private * priv,
+ t_u8 wait_option, mlan_802_11_ssid * req_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+
+ if (req_ssid && req_ssid->ssid_len != 0) {
+ /* Specific SSID scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_SPECIFIC_SSID;
+
+ memcpy(scan->param.scan_req.scan_ssid.ssid,
+ req_ssid->ssid, MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len));
+ scan->param.scan_req.scan_ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len);
+ } else {
+ /* Normal scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Change Adhoc Channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param channel The channel to be set.
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+woal_change_adhoc_chan(moal_private * priv, int channel)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ /* Get BSS information */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss_info.bss_mode == MLAN_BSS_MODE_INFRA) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Get current channel */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss->param.bss_chan.channel == (unsigned int) channel) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ PRINTM(MINFO, "Updating Channel from %d to %d\n",
+ (int) bss->param.bss_chan.channel, channel);
+
+ if (bss_info.media_connected != MTRUE) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Do disonnect */
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ memset((t_u8 *) & bss->param.bssid, 0, ETH_ALEN);
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &bss_info.ssid)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Start/Join Adhoc network */
+ bss->sub_command = MLAN_OID_BSS_START;
+ memset(&bss->param.ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&bss->param.ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Find the best network to associate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_find_best_network(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *mac = 0;
+
+ ENTER();
+
+ if (!ssid_bssid) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ bss->sub_command = MLAN_OID_BSS_FIND_BSS;
+
+ memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ memcpy(ssid_bssid, &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid));
+ mac = (t_u8 *) & ssid_bssid->bssid;
+ PRINTM(MINFO,
+ "Find network: ssid=%s, %02x:%02x:%02x:%02x:%02x:%02x, idx=%d\n",
+ ssid_bssid->ssid.ssid, mac[0], mac[1], mac[2], mac[3], mac[4],
+ mac[5], (int) ssid_bssid->idx);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode A pointer to authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 * auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && auth_mode) {
+ *auth_mode = sec->param.auth_mode;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode A pointer to encrypt mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && encrypt_mode) {
+ *encrypt_mode = sec->param.encrypt_mode;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get WPA enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable A pointer to wpa enable status
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 * enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && enable) {
+ *enable = sec->param.wpa_enabled;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode Authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.auth_mode = auth_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode Encryption mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, t_u32 encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_mode = encrypt_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set wpa enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wpa_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief enable wep key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_enable_wep_key(moal_private * priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_disable = MFALSE;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Request user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_cfg A pointer to wlan_user_scan_config structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_userscan(moal_private * priv,
+ t_u8 wait_option, wlan_user_scan_cfg * scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ sizeof(wlan_user_scan_cfg));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(scan->param.user_scan.scan_cfg_buf, scan_cfg,
+ sizeof(wlan_user_scan_cfg));
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set scan time
+ *
+ * @param priv A pointer to moal_private structure
+ * @param passive_scan_time passive scan time
+ * @param specific_scan_time specific scan time
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status
+woal_set_scan_time(moal_private * priv, t_u16 passive_scan_time,
+ t_u16 specific_scan_time)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan->param.scan_cfg.scan_time.specific_scan_time = specific_scan_time;
+ scan->param.scan_cfg.scan_time.passive_scan_time = passive_scan_time;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief request scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_cfg A pointer to wlan_user_scan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+ if (!scan_cfg) {
+ ret = woal_request_scan(priv, MOAL_NO_WAIT, NULL);
+ } else {
+ ret = woal_request_userscan(priv, MOAL_NO_WAIT, scan_cfg);
+ }
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief find ssid in scan_table
+ *
+ * @param priv A pointer to moal_private
+ * @ssid_bssid A pointer to mlan_ssid_bssid structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
+ */
+int
+woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid)
+{
+ int ret = 0;
+ mlan_scan_resp scan_resp;
+ struct timeval t;
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ do_gettimeofday(&t);
+/** scan result timeout value */
+#define SCAN_RESULT_AGEOUT 10
+ if (t.tv_sec > (scan_resp.age_in_secs + SCAN_RESULT_AGEOUT)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = woal_find_best_network(priv, MOAL_IOCTL_WAIT, ssid_bssid);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_cfg A pointer to wlan_bgscan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_bgscan(moal_private * priv,
+ t_u8 wait_option, wlan_bgscan_cfg * scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ sizeof(wlan_bgscan_cfg));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_BGSCAN_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(scan->param.user_scan.scan_cfg_buf, scan_cfg,
+ sizeof(wlan_bgscan_cfg));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set bgscan config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_bg_scan(moal_private * priv, char *buf, int length)
+{
+ t_u8 *ptr = buf + strlen("BGSCAN-CONFIG") + 1;
+ int buf_left = length - (strlen("BGSCAN-CONFIG") + 1);
+ int band = 0;
+ int num_ssid = 0;
+ int ssid_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
+ priv->scan_cfg.report_condition = BG_SCAN_SSID_MATCH;
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case WEXT_CSCAN_SSID_SECTION:
+ ssid_len = *(ptr + 1);
+ if ((buf_left < (ssid_len + 2)) ||
+ (ssid_len > MLAN_MAX_SSID_LENGTH)) {
+ PRINTM(MERROR, "Invalid ssid, buf_left=%d, ssid_len=%d\n",
+ buf_left, ssid_len);
+ buf_left = 0;
+ break;
+ }
+ if (ssid_len && (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) {
+ strncpy(priv->scan_cfg.ssid_list[num_ssid].ssid, ptr + 2,
+ ssid_len);
+ priv->scan_cfg.ssid_list[num_ssid].max_len = 0;
+ PRINTM(MIOCTL, "BG scan: ssid=%s\n",
+ priv->scan_cfg.ssid_list[num_ssid].ssid);
+ num_ssid++;
+ }
+ buf_left -= ssid_len + 2;
+ ptr += ssid_len + 2;
+ break;
+ case WEXT_BGSCAN_RSSI_SECTION:
+ priv->scan_cfg.report_condition = BG_SCAN_SSID_RSSI_MATCH;
+ priv->scan_cfg.rssi_threshold = ptr[1];
+ PRINTM(MIOCTL, "BG scan: rssi_threshold=%d\n",
+ (int) priv->scan_cfg.rssi_threshold);
+ ptr += 2;
+ buf_left -= 2;
+ break;
+ case WEXT_BGSCAN_REPEAT_SECTION:
+ priv->scan_cfg.repeat_count = (t_u16) ptr[1];
+ PRINTM(MIOCTL, "BG scan: repeat_count=%d\n",
+ (int) priv->scan_cfg.repeat_count);
+ ptr += 2;
+ buf_left -= 2;
+ break;
+ case WEXT_BGSCAN_INTERVAL_SECTION:
+ priv->scan_cfg.scan_interval = (ptr[2] << 8 | ptr[1]) * 1000;
+ PRINTM(MIOCTL, "BG scan: scan_interval=%d\n",
+ (int) priv->scan_cfg.scan_interval);
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+ /** set bgscan when ssid_num > 0 */
+ if (num_ssid) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ switch (band) {
+ case WIFI_FREQUENCY_BAND_2GHZ:
+ priv->scan_cfg.chan_list[0].radio_type = 0 | BAND_SPECIFIED;
+ break;
+ case WIFI_FREQUENCY_BAND_5GHZ:
+ priv->scan_cfg.chan_list[0].radio_type = 1 | BAND_SPECIFIED;
+ break;
+ default:
+ break;
+ }
+ priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
+ priv->scan_cfg.action = BG_SCAN_ACT_SET;
+ priv->scan_cfg.enable = MTRUE;
+ ret = woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &priv->scan_cfg);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief stop bg scan
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_stop_bg_scan(moal_private * priv)
+{
+ wlan_bgscan_cfg scan_cfg;
+ ENTER();
+
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ scan_cfg.action = BG_SCAN_ACT_SET;
+ scan_cfg.enable = MFALSE;
+ return woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &scan_cfg);
+
+ LEAVE();
+}
+
+/**
+ * @brief set bgscan config
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+void
+woal_reconfig_bgscan(moal_handle * handle)
+{
+ int i;
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
+ if (handle->priv[i]->bg_scan_start &&
+ handle->priv[i]->bg_scan_reported) {
+ PRINTM(MIOCTL, "Reconfig BGSCAN\n");
+ woal_request_bgscan(handle->priv[i], MOAL_NO_WAIT,
+ &handle->priv[i]->scan_cfg);
+ handle->priv[i]->bg_scan_reported = MFALSE;
+ }
+ }
+ }
+}
+
+/**
+ * @brief set rssi low threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rssi A pointer to low rssi
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_rssi_low_threshold(moal_private * priv, char *rssi)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int low_rssi = 0;
+
+ ENTER();
+ if (priv->media_connected == MFALSE)
+ goto done;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
+ req->action = MLAN_ACT_SET;
+ misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW;
+ misc->param.subscribe_event.evt_bitmap |= SUBSCRIBE_EVT_PRE_BEACON_LOST;
+ misc->param.subscribe_event.pre_beacon_miss = DEFAULT_PRE_BEACON_MISS;
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&low_rssi, rssi)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef STA_CFG80211
+ priv->mrvl_rssi_low = low_rssi;
+#endif
+ misc->param.subscribe_event.low_rssi = low_rssi;
+ misc->param.subscribe_event.low_rssi_freq = 0;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_CFG80211
+/**
+ * @brief set rssi low threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event_id event id.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_rssi_threshold(moal_private * priv, t_u32 event_id)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+ if (priv->media_connected == MFALSE)
+ goto done;
+ if (priv->mrvl_rssi_low)
+ goto done;
+ if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_LOW) {
+ if (priv->last_rssi_low < 100)
+ priv->last_rssi_low += priv->cqm_rssi_hyst;
+ priv->last_rssi_high = abs(priv->cqm_rssi_thold);
+ } else if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_HIGH) {
+ priv->last_rssi_low = abs(priv->cqm_rssi_thold);
+ if (priv->last_rssi_high > priv->cqm_rssi_hyst)
+ priv->last_rssi_high -= priv->cqm_rssi_hyst;
+ } else {
+ priv->last_rssi_low = abs(priv->cqm_rssi_thold);
+ priv->last_rssi_high = abs(priv->cqm_rssi_thold);
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
+ req->action = MLAN_ACT_SET;
+ misc->param.subscribe_event.evt_bitmap =
+ SUBSCRIBE_EVT_RSSI_LOW | SUBSCRIBE_EVT_RSSI_HIGH;
+ misc->param.subscribe_event.low_rssi_freq = 0;
+ misc->param.subscribe_event.low_rssi = priv->last_rssi_low;
+ misc->param.subscribe_event.high_rssi_freq = 0;
+ misc->param.subscribe_event.high_rssi = priv->last_rssi_high;
+ PRINTM(MIOCTL, "rssi_low=%d, rssi_high=%d\n", (int) priv->last_rssi_low,
+ (int) priv->last_rssi_high);
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param powermode A pointer to powermode buf
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_powermode(moal_private * priv, int *powermode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int ps_mode;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_GET, &ps_mode, 0)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (ps_mode)
+ *powermode = MFALSE;
+ else
+ *powermode = MTRUE;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set scan type
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_scan_type(moal_private * priv, t_u32 scan_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan->param.scan_cfg.scan_type = scan_type;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param powermode A pointer to powermode string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_powermode(moal_private * priv, char *powermode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int disabled;
+
+ ENTER();
+
+ if (*powermode == '1') {
+ PRINTM(MIOCTL, "Disable power save\n");
+ disabled = 1;
+ } else if (*powermode == '0') {
+ PRINTM(MIOCTL, "Enable power save\n");
+ disabled = 0;
+ } else {
+ PRINTM(MERROR, "unsupported power mode\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, 0))
+ ret = MLAN_STATUS_FAILURE;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set combo scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_set_combo_scan(moal_private * priv, char *buf, int length)
+{
+ int ret = 0;
+ wlan_user_scan_cfg scan_cfg;
+ t_u8 *ptr = buf + WEXT_CSCAN_HEADER_SIZE;
+ int buf_left = length - WEXT_CSCAN_HEADER_SIZE;
+ int num_ssid = 0;
+ int num_chan = 0;
+ int ssid_len = 0;
+ int i = 0;
+ t_u16 passive_scan_time = 0;
+ t_u16 specific_scan_time = 0;
+
+ ENTER();
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case WEXT_CSCAN_SSID_SECTION:
+ ssid_len = *(ptr + 1);
+ if ((buf_left < (ssid_len + 2)) ||
+ (ssid_len > MLAN_MAX_SSID_LENGTH)) {
+ PRINTM(MERROR, "Invalid ssid, buf_left=%d, ssid_len=%d\n",
+ buf_left, ssid_len);
+ buf_left = 0;
+ break;
+ }
+ if (ssid_len && (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) {
+ strncpy(scan_cfg.ssid_list[num_ssid].ssid, ptr + 2, ssid_len);
+ scan_cfg.ssid_list[num_ssid].max_len = 0;
+ PRINTM(MIOCTL, "Combo scan: ssid=%s\n",
+ scan_cfg.ssid_list[num_ssid].ssid);
+ num_ssid++;
+ }
+ buf_left -= ssid_len + 2;
+ ptr += ssid_len + 2;
+ break;
+ case WEXT_CSCAN_CHANNEL_SECTION:
+ num_chan = ptr[1];
+ if ((buf_left < (num_chan + 2)) ||
+ (num_chan > WLAN_USER_SCAN_CHAN_MAX)) {
+ PRINTM(MERROR,
+ "Invalid channel list, buf_left=%d, num_chan=%d\n",
+ buf_left, num_chan);
+ buf_left = 0;
+ break;
+ }
+ for (i = 0; i < num_chan; i++) {
+ scan_cfg.chan_list[i].chan_number = ptr[2 + i];
+ PRINTM(MIOCTL, "Combo scan: chan=%d\n",
+ scan_cfg.chan_list[i].chan_number);
+ }
+ buf_left -= 2 + num_chan;
+ ptr += 2 + num_chan;
+ break;
+ case WEXT_CSCAN_PASV_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR, "Invalid PASV_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ passive_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ case WEXT_CSCAN_HOME_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR, "Invalid HOME_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ specific_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+ if (passive_scan_time || specific_scan_time) {
+ PRINTM(MIOCTL, "Set passive_scan_time=%d specific_scan_time=%d\n",
+ passive_scan_time, specific_scan_time);
+ if (MLAN_STATUS_FAILURE ==
+ woal_set_scan_time(priv, passive_scan_time, specific_scan_time)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (num_ssid || num_chan) {
+ if (num_ssid) {
+ /* Add broadcast scan to ssid_list */
+ scan_cfg.ssid_list[num_ssid].max_len = 0xff;
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ }
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg))
+ ret = -EFAULT;
+ if (num_ssid && (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE))
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+ } else {
+ /* request broadcast scan */
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, NULL))
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get band
+ *
+ * @param priv A pointer to moal_private structure
+ * @param band A pointer to band buf
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_band(moal_private * priv, int *band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ int support_band = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (radio_cfg->param.band_cfg.config_bands & (BAND_B | BAND_G | BAND_GN))
+ support_band |= WIFI_FREQUENCY_BAND_2GHZ;
+ if (radio_cfg->param.band_cfg.config_bands & (BAND_A | BAND_AN))
+ support_band |= WIFI_FREQUENCY_BAND_5GHZ;
+ *band = support_band;
+ if (support_band == WIFI_FREQUENCY_ALL_BAND)
+ *band = WIFI_FREQUENCY_BAND_AUTO;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set band
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pband A pointer to band string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_band(moal_private * priv, char *pband)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int band = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ /* Get fw supported values from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (*pband == '0') {
+ PRINTM(MIOCTL, "Set band to AUTO\n");
+ band = radio_cfg->param.band_cfg.fw_bands;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ if (radio_cfg->param.band_cfg.fw_bands & BAND_A)
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &cfg80211_band_5ghz;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ }
+#endif
+ } else if (*pband == '1') {
+ PRINTM(MIOCTL, "Set band to 5G\n");
+ if (!(radio_cfg->param.band_cfg.fw_bands & BAND_A)) {
+ PRINTM(MERROR, "Don't support 5G band\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ band = BAND_A;
+ band |= BAND_AN;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ }
+#endif
+ } else if (*pband == '2') {
+ PRINTM(MIOCTL, "Set band to 2G\n");
+ band = BAND_B | BAND_G;
+ band |= BAND_GN;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ }
+#endif
+ } else {
+ PRINTM(MERROR, "unsupported band\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Set config_bands to MLAN */
+ req->action = MLAN_ACT_SET;
+ memset(&radio_cfg->param.band_cfg, 0, sizeof(mlan_ds_band_cfg));
+ radio_cfg->param.band_cfg.config_bands = band;
+ radio_cfg->param.band_cfg.adhoc_start_band = band;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add RX Filter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rxfilter A pointer to rxfilter string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_add_rxfilter(moal_private * priv, char *rxfilter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ /* Android command: "DRIVER RXFILTER-ADD 0" "DRIVER RXFILTER-ADD 1" "DRIVER
+ RXFILTER-ADD 3" */
+ if (*rxfilter == '0') {
+ PRINTM(MIOCTL, "Add IPV4 multicast filter\n");
+ priv->rx_filter |= RX_FILTER_IPV4_MULTICAST;
+ } else if (*rxfilter == '1') {
+ PRINTM(MIOCTL, "Add broadcast filter\n");
+ priv->rx_filter |= RX_FILTER_BROADCAST;
+ } else if (*rxfilter == '2') {
+ PRINTM(MIOCTL, "Add unicast filter\n");
+ priv->rx_filter |= RX_FILTER_UNICAST;
+ } else if (*rxfilter == '3') {
+ PRINTM(MIOCTL, "Add IPV6 multicast fitler\n");
+ priv->rx_filter |= RX_FILTER_IPV6_MULTICAST;
+ } else {
+ PRINTM(MERROR, "unsupported rx fitler\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Remove RX Filter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rxfilter A pointer to rxfilter string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_remove_rxfilter(moal_private * priv, char *rxfilter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if (*rxfilter == '0') {
+ PRINTM(MIOCTL, "Remove IPV4 multicast filter\n");
+ priv->rx_filter &= ~RX_FILTER_IPV4_MULTICAST;
+ } else if (*rxfilter == '1') {
+ PRINTM(MIOCTL, "Remove broadcast filter\n");
+ priv->rx_filter &= ~RX_FILTER_BROADCAST;
+ } else if (*rxfilter == '2') {
+ PRINTM(MIOCTL, "Remove unicast filter\n");
+ priv->rx_filter &= ~RX_FILTER_UNICAST;
+ } else if (*rxfilter == '3') {
+ PRINTM(MIOCTL, "Remove IPV6 multicast fitler\n");
+ priv->rx_filter &= ~RX_FILTER_IPV6_MULTICAST;
+ } else {
+ PRINTM(MERROR, "unsupported rx fitler\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param qos_cfg A pointer to QoS configuration structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_qos_cfg(moal_private * priv, char *qos_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int qosinfo = 0;
+
+ ENTER();
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&qosinfo, qos_cfg)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MIOCTL, "set qosinfo=%d\n", qosinfo);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg->param.qos_cfg = (t_u8) qosinfo;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param psleeppd A pointer to sleep period configuration structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+int
+woal_set_sleeppd(moal_private * priv, char *psleeppd)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int sleeppd = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&sleeppd, psleeppd)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MIOCTL, "set sleeppd=%d\n", sleeppd);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if ((sleeppd <= MAX_SLEEP_PERIOD && sleeppd >= MIN_SLEEP_PERIOD) ||
+ (sleeppd == 0)
+ || (sleeppd == SLEEP_PERIOD_RESERVED_FF)
+ ) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = sleeppd;
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c
new file mode 100644
index 000000000000..d5bed42fa73d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c
@@ -0,0 +1,4036 @@
+/** @file moal_main.c
+ *
+ * @brief This file contains the major functions in WLAN
+ * driver.
+ *
+ * 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 "moal_main.h"
+#include "moal_sdio.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+#include "moal_sta_cfg80211.h"
+#endif
+#endif
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+#include "moal_uap_cfg80211.h"
+#endif
+#endif
+#include <linux/platform_device.h>
+#include <linux/wlan_plat.h>
+#include "moal_eth_ioctl.h"
+
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+#define KERN_VERSION "26"
+
+/** Driver version */
+char driver_version[] =
+ "SD8797-%s-M2614" MLAN_RELEASE_VERSION "-GPL" "-(" "FP" FPNUM ")"
+#ifdef DEBUG_LEVEL2
+ "-dbg"
+#endif
+ " ";
+
+/** Firmware name */
+char *fw_name = NULL;
+int req_fw_nowait = 0;
+
+/** MAC address */
+char *mac_addr = NULL;
+
+#ifdef MFG_CMD_SUPPORT
+/** Mfg mode */
+int mfg_mode = 0;
+#endif
+
+/** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+int intmode = INT_MODE_SDIO;
+/** GPIO interrupt pin number */
+int gpiopin = 0;
+
+/** Auto deep sleep */
+int auto_ds = 0;
+
+/** IEEE PS mode */
+int ps_mode = 0;
+
+/** Max Tx buffer size */
+int max_tx_buf = 0;
+
+#ifdef STA_SUPPORT
+/** Max STA interfaces */
+int max_sta_bss = DEF_STA_BSS;
+#endif
+
+#ifdef UAP_SUPPORT
+/** Max uAP interfaces */
+int max_uap_bss = DEF_UAP_BSS;
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Max WIFIDIRECT interfaces */
+int max_wfd_bss = DEF_WIFIDIRECT_BSS;
+#endif
+
+#ifdef SDIO_SUSPEND_RESUME
+/** PM keep power */
+int pm_keep_power = 1;
+#endif
+
+#if defined(STA_SUPPORT)
+/** 802.11d configuration */
+int cfg_11d = 0;
+#endif
+
+/** CAL data config file */
+char *cal_data_cfg = NULL;
+/** Init config file (MAC address, register etc.) */
+char *init_cfg = NULL;
+
+/** Enable minicard power-up/down */
+int minicard_pwrup = 1;
+/** Pointer to struct with control hooks */
+struct wifi_platform_data *wifi_control_data = NULL;
+
+int cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK;
+
+/** woal_callbacks */
+static mlan_callbacks woal_callbacks = {
+ .moal_get_fw_data = moal_get_fw_data,
+ .moal_init_fw_complete = moal_init_fw_complete,
+ .moal_shutdown_fw_complete = moal_shutdown_fw_complete,
+ .moal_send_packet_complete = moal_send_packet_complete,
+ .moal_recv_packet = moal_recv_packet,
+ .moal_recv_event = moal_recv_event,
+ .moal_ioctl_complete = moal_ioctl_complete,
+ .moal_alloc_mlan_buffer = moal_alloc_mlan_buffer,
+ .moal_free_mlan_buffer = moal_free_mlan_buffer,
+ .moal_write_reg = moal_write_reg,
+ .moal_read_reg = moal_read_reg,
+ .moal_write_data_sync = moal_write_data_sync,
+ .moal_read_data_sync = moal_read_data_sync,
+ .moal_malloc = moal_malloc,
+ .moal_mfree = moal_mfree,
+ .moal_memset = moal_memset,
+ .moal_memcpy = moal_memcpy,
+ .moal_memmove = moal_memmove,
+ .moal_memcmp = moal_memcmp,
+ .moal_udelay = moal_udelay,
+ .moal_get_system_time = moal_get_system_time,
+ .moal_init_timer = moal_init_timer,
+ .moal_free_timer = moal_free_timer,
+ .moal_start_timer = moal_start_timer,
+ .moal_stop_timer = moal_stop_timer,
+ .moal_init_lock = moal_init_lock,
+ .moal_free_lock = moal_free_lock,
+ .moal_spin_lock = moal_spin_lock,
+ .moal_spin_unlock = moal_spin_unlock,
+ .moal_print = moal_print,
+ .moal_print_netintf = moal_print_netintf,
+ .moal_assert = moal_assert,
+};
+
+/** Default Driver mode */
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(WIFI_DIRECT_SUPPORT)
+int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP | DRV_MODE_WIFIDIRECT);
+#else
+int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP);
+#endif
+#else
+#ifdef STA_SUPPORT
+int drv_mode = DRV_MODE_STA;
+#else
+int drv_mode = DRV_MODE_UAP;
+#endif /* STA_SUPPORT */
+#endif /* STA_SUPPORT & UAP_SUPPORT */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/** Semaphore for add/remove card */
+struct semaphore AddRemoveCardSem;
+/**
+ * the maximum number of adapter supported
+ **/
+#define MAX_MLAN_ADAPTER 2
+/**
+ * The global variable of a pointer to moal_handle
+ * structure variable
+ **/
+moal_handle *m_handle[MAX_MLAN_ADAPTER];
+
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
+#endif /* DEBUG_LEVEL2 */
+t_u32 drvdbg = DEFAULT_DEBUG_MASK;
+#endif /* DEBUG_LEVEL1 */
+
+int woal_open(struct net_device *dev);
+int woal_close(struct net_device *dev);
+int woal_set_mac_address(struct net_device *dev, void *addr);
+void woal_tx_timeout(struct net_device *dev);
+struct net_device_stats *woal_get_stats(struct net_device *dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb);
+#endif
+
+mlan_debug_info info;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function dynamically populates the driver mode table
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param drv_mode_local Driver mode
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_update_drv_tbl(moal_handle * handle, int drv_mode_local)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ unsigned int intf_num = 0;
+ int i = 0, j = 0;
+ mlan_bss_attr *bss_tbl = NULL;
+
+ ENTER();
+
+ /* Calculate number of interfaces */
+#ifdef STA_SUPPORT
+ if (drv_mode_local & DRV_MODE_STA) {
+ if ((max_sta_bss < 1) || (max_sta_bss > MAX_STA_BSS)) {
+ PRINTM(MWARN, "Unsupported max_sta_bss (%d), setting to default\n",
+ max_sta_bss);
+ max_sta_bss = DEF_STA_BSS;
+ }
+ intf_num += max_sta_bss;
+ }
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+ if (drv_mode_local & DRV_MODE_UAP) {
+ if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) {
+ PRINTM(MWARN, "Unsupported max_uap_bss (%d), setting to default\n",
+ max_uap_bss);
+ max_uap_bss = DEF_UAP_BSS;
+ }
+ intf_num += max_uap_bss;
+ }
+#endif /* UAP_SUPPORT */
+
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
+ if ((max_wfd_bss < 1) || (max_wfd_bss > MAX_WIFIDIRECT_BSS)) {
+ PRINTM(MWARN, "Unsupported max_wfd_bss (%d), setting to default\n",
+ max_wfd_bss);
+ max_wfd_bss = DEF_WIFIDIRECT_BSS;
+ }
+ intf_num += max_wfd_bss;
+ }
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ /* Create BSS attribute table */
+ if ((intf_num == 0) || (intf_num > MLAN_MAX_BSS_NUM)) {
+ PRINTM(MERROR, "Unsupported number of BSS %d\n", intf_num);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ /* Create new table */
+ if (!
+ (bss_tbl =
+ (mlan_bss_attr *) kmalloc(sizeof(mlan_bss_attr) * intf_num,
+ GFP_KERNEL))) {
+ PRINTM(MERROR, "Could not create BSS attribute table\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Populate BSS attribute table */
+#ifdef STA_SUPPORT
+ if (drv_mode_local & DRV_MODE_STA) {
+ for (j = 0; j < max_sta_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_STA;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ i++;
+ }
+ }
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+ if (drv_mode_local & DRV_MODE_UAP) {
+ for (j = 0; j < max_uap_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_UAP;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ i++;
+ }
+ }
+#endif /* UAP_SUPPORT */
+
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
+ for (j = 0; j < max_wfd_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ i++;
+ }
+ }
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ /* Clear existing table, if any */
+ if (handle->drv_mode.bss_attr != NULL) {
+ kfree(handle->drv_mode.bss_attr);
+ handle->drv_mode.bss_attr = NULL;
+ }
+
+ /* Create moal_drv_mode entry */
+ handle->drv_mode.drv_mode = drv_mode;
+ handle->drv_mode.intf_num = intf_num;
+ handle->drv_mode.bss_attr = bss_tbl;
+ if (fw_name) {
+ handle->drv_mode.fw_name = fw_name;
+ } else {
+#if defined(UAP_SUPPORT) && defined(STA_SUPPORT)
+ handle->drv_mode.fw_name = DEFAULT_AP_STA_FW_NAME;
+#else
+#ifdef UAP_SUPPORT
+ handle->drv_mode.fw_name = DEFAULT_AP_FW_NAME;
+#else
+ handle->drv_mode.fw_name = DEFAULT_FW_NAME;
+#endif /* UAP_SUPPORT */
+#endif /* UAP_SUPPORT && STA_SUPPORT */
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes software
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_init_sw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ unsigned int i;
+ mlan_device device;
+ t_void *pmlan;
+
+ ENTER();
+
+ /* Initialize moal_handle structure */
+ handle->hardware_status = HardwareStatusInitializing;
+ handle->main_state = MOAL_STATE_IDLE;
+
+#ifdef STA_SUPPORT
+ if (MTRUE
+#ifdef STA_WEXT
+ && !IS_STA_WEXT(cfg80211_wext)
+#endif
+#ifdef STA_CFG80211
+ && !IS_STA_CFG80211(cfg80211_wext)
+#endif
+ ) {
+ PRINTM(MERROR, "STA without WEXT or CFG80211 bit definition!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif /* STA_SUPPORT */
+
+ if (woal_update_drv_tbl(handle, drv_mode) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not update driver mode table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* PnP and power profile */
+ handle->surprise_removed = MFALSE;
+ init_waitqueue_head(&handle->init_wait_q);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ spin_lock_init(&handle->queue_lock);
+#endif
+
+#if defined(SDIO_SUSPEND_RESUME)
+ handle->is_suspended = MFALSE;
+ handle->hs_activated = MFALSE;
+ handle->suspend_fail = MFALSE;
+#ifdef SDIO_SUSPEND_RESUME
+ handle->suspend_notify_req = MFALSE;
+#endif
+ handle->hs_skip_count = 0;
+ handle->hs_force_count = 0;
+ handle->cmd52_func = 0;
+ handle->cmd52_reg = 0;
+ handle->cmd52_val = 0;
+ init_waitqueue_head(&handle->hs_activate_wait_q);
+#endif
+
+ /* Initialize measurement wait queue */
+ handle->meas_wait_q_woken = MFALSE;
+ handle->meas_start_jiffies = 0;
+ handle->cac_period = MFALSE;
+ handle->delay_bss_start = MFALSE;
+ init_waitqueue_head(&handle->meas_wait_q);
+#ifdef DFS_TESTING_SUPPORT
+ handle->cac_period_jiffies = 0;
+#endif
+
+#ifdef REASSOCIATION
+ MOAL_INIT_SEMAPHORE(&handle->reassoc_sem);
+ handle->reassoc_on = 0;
+
+ /* Initialize the timer for the reassociation */
+ woal_initialize_timer(&handle->reassoc_timer,
+ woal_reassoc_timer_func, handle);
+
+ handle->is_reassoc_timer_set = MFALSE;
+#endif /* REASSOCIATION */
+
+ /* Register to MLAN */
+ memset(&device, 0, sizeof(mlan_device));
+ device.pmoal_handle = handle;
+
+#ifdef MFG_CMD_SUPPORT
+ device.mfg_mode = (t_u32) mfg_mode;
+#endif
+ device.int_mode = (t_u32) intmode;
+ device.gpio_pin = (t_u32) gpiopin;
+#ifdef DEBUG_LEVEL1
+ device.drvdbg = drvdbg;
+#endif
+ device.auto_ds = (t_u32) auto_ds;
+ device.ps_mode = (t_u32) ps_mode;
+ device.max_tx_buf = (t_u32) max_tx_buf;
+#if defined(STA_SUPPORT)
+ device.cfg_11d = (t_u32) cfg_11d;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
+#else
+ device.mpa_tx_cfg = MLAN_INIT_PARA_DISABLED;
+#endif
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
+#else
+ device.mpa_rx_cfg = MLAN_INIT_PARA_DISABLED;
+#endif
+#endif
+
+ for (i = 0; i < handle->drv_mode.intf_num; i++) {
+ device.bss_attr[i].bss_type = handle->drv_mode.bss_attr[i].bss_type;
+ device.bss_attr[i].frame_type = handle->drv_mode.bss_attr[i].frame_type;
+ device.bss_attr[i].active = handle->drv_mode.bss_attr[i].active;
+ device.bss_attr[i].bss_priority =
+ handle->drv_mode.bss_attr[i].bss_priority;
+ device.bss_attr[i].bss_num = handle->drv_mode.bss_attr[i].bss_num;
+ }
+ memcpy(&device.callbacks, &woal_callbacks, sizeof(mlan_callbacks));
+
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan))
+ handle->pmlan_adapter = pmlan;
+ else
+ ret = MLAN_STATUS_FAILURE;
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of moal_handle
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void
+woal_free_moal_handle(moal_handle * handle)
+{
+ ENTER();
+ if (!handle) {
+ PRINTM(MERROR, "The handle is NULL\n");
+ LEAVE();
+ return;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+ if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) {
+ sock_release((handle->nl_sk)->sk_socket);
+ handle->nl_sk = NULL;
+ }
+#else
+ netlink_kernel_release(handle->nl_sk);
+#endif
+
+ if (handle->pmlan_adapter)
+ mlan_unregister(handle->pmlan_adapter);
+
+ /* Free BSS attribute table */
+ if (handle->drv_mode.bss_attr != NULL) {
+ kfree(handle->drv_mode.bss_attr);
+ handle->drv_mode.bss_attr = NULL;
+ }
+ PRINTM(MINFO, "Free Adapter\n");
+ if (handle->malloc_count || handle->lock_count || handle->mbufalloc_count) {
+ PRINTM(MERROR,
+ "mlan has memory leak: malloc_count=%u lock_count=%u mbufalloc_count=%u\n",
+ handle->malloc_count, handle->lock_count,
+ handle->mbufalloc_count);
+ }
+ /* Free the moal handle itself */
+ kfree(handle);
+ LEAVE();
+}
+
+/**
+ * @brief WOAL get one line data from ASCII format data
+ *
+ * @param data Source data
+ * @param size Source data length
+ * @param line_pos Destination data
+ * @return routnine status
+ */
+static t_size
+parse_cfg_get_line(t_u8 * data, t_size size, t_u8 * line_pos)
+{
+ t_u8 *src, *dest;
+ static t_s32 pos = 0;
+
+ ENTER();
+
+ if (pos >= size) { /* reach the end */
+ pos = 0; /* Reset position for rfkill */
+ LEAVE();
+ return -1;
+ }
+ memset(line_pos, 0, MAX_LINE_LEN);
+ src = data + pos;
+ dest = line_pos;
+
+ while (*src != '\x0A' && *src != '\0') {
+ if (*src != ' ' && *src != '\t') /* parse space */
+ *dest++ = *src++;
+ else
+ src++;
+ pos++;
+ }
+ /* parse new line */
+ pos++;
+ *dest = '\0';
+ LEAVE();
+ return strlen(line_pos);
+}
+
+/**
+ * @brief Process register access request
+ * @param type_string String format Register type
+ * @param offset_string String format Register offset
+ * @param value_string String format Pointer to value
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32
+woal_process_regrdwr(moal_handle * handle, t_u8 * type_string,
+ t_u8 * offset_string, t_u8 * value_string)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ int type, offset, value;
+ pmlan_ioctl_req ioctl_req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+
+ ENTER();
+
+ /* Alloc ioctl_req */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+
+ if (ioctl_req == NULL) {
+ PRINTM(MERROR, "Can't alloc memory\n");
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&type, type_string)) {
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&offset, offset_string)) {
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&value, value_string)) {
+ goto done;
+ }
+
+ ioctl_req->req_id = MLAN_IOCTL_REG_MEM;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ reg = (mlan_ds_reg_mem *) ioctl_req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ if (type < 5) {
+ reg->param.reg_rw.type = type;
+ } else {
+ PRINTM(MERROR, "Unsupported Type\n");
+ goto done;
+ }
+ reg->param.reg_rw.offset = offset;
+ reg->param.reg_rw.value = value;
+
+ /* request ioctl for STA */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(handle->priv[0], ioctl_req, MOAL_IOCTL_WAIT)) {
+ goto done;
+ }
+ PRINTM(MINFO, "Register type: %d, offset: 0x%x, value: 0x%x\n", type,
+ offset, value);
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WOAL parse ASCII format data to MAC address
+ *
+ * @param handle MOAL handle
+ * @param data Source data
+ * @param size data length
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32
+woal_process_init_cfg(moal_handle * handle, t_u8 * data, t_size size)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *pos;
+ t_u8 *intf_s, *intf_e;
+ t_u8 s[MAX_LINE_LEN]; /* 1 line data */
+ t_size line_len;
+ t_u8 index = 0;
+ t_u32 i;
+ t_u8 bss_mac_addr[MAX_MAC_ADDR_LEN];
+ t_u8 bss_mac_name[MAX_PARAM_LEN];
+ t_u8 type[MAX_PARAM_LEN];
+ t_u8 offset[MAX_PARAM_LEN];
+ t_u8 value[MAX_PARAM_LEN];
+
+ ENTER();
+
+ while ((line_len = parse_cfg_get_line(data, size, s)) != -1) {
+
+ pos = s;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') ||
+ *pos == '\n' || *pos == '\0')
+ continue; /* Needn't process this line */
+
+ /* Process MAC addr */
+ if (strncmp(pos, "mac_addr", 8) == 0) {
+ intf_s = strchr(pos, '=');
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ':');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ strncpy(bss_mac_addr, intf_e + 1, MAX_MAC_ADDR_LEN - 1);
+ bss_mac_addr[MAX_MAC_ADDR_LEN - 1] = '\0';
+ if ((intf_e - intf_s) > MAX_PARAM_LEN) {
+ PRINTM(MERROR, "Too long interface name %d\n", __LINE__);
+ goto done;
+ }
+ strncpy(bss_mac_name, intf_s + 1, intf_e - intf_s - 1);
+ bss_mac_name[intf_e - intf_s - 1] = '\0';
+ for (i = 0; i < handle->priv_num; i++) {
+ if (strcmp(bss_mac_name, handle->priv[i]->netdev->name) ==
+ 0) {
+ memset(handle->priv[i]->current_addr, 0, ETH_ALEN);
+ PRINTM(MINFO, "Interface name: %s mac: %s\n",
+ bss_mac_name, bss_mac_addr);
+ woal_mac2u8(handle->priv[i]->current_addr,
+ bss_mac_addr);
+ /* Set WLAN MAC addresses */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_set_mac_address(handle->priv[i])) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ goto done;
+ }
+ memcpy(handle->priv[i]->netdev->dev_addr,
+ handle->priv[i]->current_addr, ETH_ALEN);
+ index++; /* Mark found one interface matching */
+ }
+ }
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+ }
+ /* Process REG value */
+ else if (strncmp(pos, "wlan_reg", 8) == 0) {
+ intf_s = strchr(pos, '=');
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ',');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ /* Copy type */
+ strncpy(type, intf_s + 1, 1);
+ type[1] = '\0';
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+ intf_s = intf_e + 1;
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ',');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ if ((intf_e - intf_s) >= MAX_PARAM_LEN) {
+ PRINTM(MERROR, "Regsier offset is too long %d\n", __LINE__);
+ goto done;
+ }
+ /* Copy offset */
+ strncpy(offset, intf_s, intf_e - intf_s);
+ offset[intf_e - intf_s] = '\0';
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+ intf_s = intf_e + 1;
+ if (intf_s != NULL) {
+ if ((strlen(intf_s) >= MAX_PARAM_LEN)) {
+ PRINTM(MERROR, "Regsier value is too long %d\n", __LINE__);
+ goto done;
+ }
+ /* Copy value */
+ strncpy(value, intf_s, sizeof(value));
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_process_regrdwr(handle, type, offset, value)) {
+ PRINTM(MERROR, "Access Reg failed\n");
+ goto done;
+ }
+ PRINTM(MINFO, "Reg type: %s, offset: %s, value: %s\n", type, offset,
+ value);
+ }
+ }
+
+ if (index == 0) {
+ PRINTM(MINFO, "Can't find any matching MAC Address");
+ }
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WOAL set user defined init data and param
+ *
+ * @param handle MOAL handle structure
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32
+woal_set_user_init_data(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *cfg_data = NULL;
+ t_size len;
+
+ ENTER();
+
+ if ((request_firmware(&handle->user_data, init_cfg, handle->hotplug_device))
+ < 0) {
+ PRINTM(MERROR, "Init config file request_firmware() failed\n");
+ goto done;
+ }
+
+ if (handle->user_data) {
+ cfg_data = (t_u8 *) (handle->user_data)->data;
+ len = (handle->user_data)->size;
+ if (MLAN_STATUS_SUCCESS != woal_process_init_cfg(handle, cfg_data, len)) {
+ PRINTM(MERROR, "Can't process init config file\n");
+ goto done;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ done:
+ if (handle->user_data)
+ release_firmware(handle->user_data);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add interfaces DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_add_card_dpc(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int i;
+
+ ENTER();
+
+#ifdef CONFIG_PROC_FS
+ /* Initialize proc fs */
+ woal_proc_init(handle);
+#endif /* CONFIG_PROC_FS */
+
+ /* Add interfaces */
+ for (i = 0; i < handle->drv_mode.intf_num; i++) {
+ if (!woal_add_interface
+ (handle, handle->priv_num, handle->drv_mode.bss_attr[i].bss_type)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ handle->priv_num++;
+ }
+ if (init_cfg) {
+ if (MLAN_STATUS_SUCCESS != woal_set_user_init_data(handle)) {
+ PRINTM(MFATAL, "Set user init data and param failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+
+ err:
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to add interface\n");
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+ handle->priv_num = 0;
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Download and Initialize firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_init_fw_dpc(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_fw_image fw;
+
+ mlan_init_param param;
+
+ ENTER();
+
+ if (handle->firmware) {
+ memset(&fw, 0, sizeof(mlan_fw_image));
+ fw.pfw_buf = (t_u8 *) handle->firmware->data;
+ fw.fw_len = handle->firmware->size;
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ ret = mlan_dnld_fw(handle->pmlan_adapter, &fw);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "WLAN: Download FW with nowwait: %d\n",
+ req_fw_nowait);
+ goto done;
+ }
+ PRINTM(MMSG, "WLAN FW is active\n");
+ }
+
+ /** Cal data request */
+ memset(&param, 0, sizeof(mlan_init_param));
+ if (cal_data_cfg) {
+ if ((request_firmware
+ (&handle->user_data, cal_data_cfg, handle->hotplug_device)) < 0) {
+ PRINTM(MERROR, "Cal data request_firmware() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ if (handle->user_data) {
+ param.pcal_data_buf = (t_u8 *) handle->user_data->data;
+ param.cal_data_len = handle->user_data->size;
+ }
+
+ handle->hardware_status = HardwareStatusFwReady;
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ handle->init_wait_q_woken = MFALSE;
+
+ ret = mlan_set_init_param(handle->pmlan_adapter, &param);
+
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ ret = mlan_init_fw(handle->pmlan_adapter);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ } else if (ret == MLAN_STATUS_SUCCESS) {
+ handle->hardware_status = HardwareStatusReady;
+ goto done;
+ }
+ /* Wait for mlan_init to complete */
+ wait_event_interruptible(handle->init_wait_q, handle->init_wait_q_woken);
+ if (handle->hardware_status != HardwareStatusReady) {
+ woal_moal_debug_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), handle,
+ MTRUE);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (handle->user_data)
+ release_firmware(handle->user_data);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param firmware A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_request_fw_dpc(moal_handle * handle, const struct firmware *firmware)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct timeval tstamp;
+
+ ENTER();
+
+ if (!firmware) {
+ do_gettimeofday(&tstamp);
+ if (tstamp.tv_sec > (handle->req_fw_time.tv_sec + REQUEST_FW_TIMEOUT)) {
+ PRINTM(MERROR, "No firmware image found. Skipping download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MERROR, "request_firmware_nowait failed for %s. Retrying..\n",
+ handle->drv_mode.fw_name);
+ woal_sched_timeout(MOAL_TIMER_1S);
+ woal_request_fw(handle);
+ LEAVE();
+ return ret;
+ }
+ handle->firmware = firmware;
+
+ if ((ret = woal_init_fw_dpc(handle)))
+ goto done;
+ if ((ret = woal_add_card_dpc(handle)))
+ goto done;
+
+ done:
+ /* We should hold the semaphore until callback finishes execution */
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void
+woal_request_fw_callback(const struct firmware *firmware, void *context)
+{
+ ENTER();
+ woal_request_fw_dpc((moal_handle *) context, firmware);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
+ if (firmware)
+ release_firmware(firmware);
+#endif
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Download firmware using helper
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_request_fw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int err;
+ t_u32 revision_id = 0;
+
+ ENTER();
+
+ if (!fw_name) {
+/** Revision ID register */
+#define REV_ID_REG 0x5c
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ woal_read_reg(handle, REV_ID_REG, &revision_id);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ /* Check revision ID */
+ switch (revision_id) {
+ case SD8797_A0:
+ handle->drv_mode.fw_name = SD8797_A0_FW_NAME;
+ break;
+ case SD8797_B0:
+ handle->drv_mode.fw_name = SD8797_B0_FW_NAME;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
+ if ((err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, GFP_KERNEL,
+ handle,
+ woal_request_fw_callback)) < 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
+ if ((err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, handle,
+ woal_request_fw_callback)) < 0) {
+#else
+ if ((err = request_firmware_nowait(THIS_MODULE,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, handle,
+ woal_request_fw_callback)) < 0) {
+#endif
+#endif
+ PRINTM(MFATAL,
+ "WLAN: request_firmware_nowait() failed, error code = %d\n",
+ err);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ if ((err =
+ request_firmware(&handle->firmware, handle->drv_mode.fw_name,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MFATAL, "WLAN: request_firmware() failed, error code = %d\n",
+ err);
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ ret = woal_request_fw_dpc(handle, handle->firmware);
+ release_firmware(handle->firmware);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_init_fw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ do_gettimeofday(&handle->req_fw_time);
+ if ((ret = woal_request_fw(handle)) < 0) {
+ PRINTM(MFATAL, "woal_request_fw failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will fill in the mlan_buffer
+ *
+ * @param pmbuf A pointer to mlan_buffer
+ * @param skb A pointer to struct sk_buff
+ *
+ * @return N/A
+ */
+static void
+woal_fill_mlan_buffer(moal_private * priv,
+ mlan_buffer * pmbuf, struct sk_buff *skb)
+{
+ struct timeval tstamp;
+ struct ethhdr *eth;
+ t_u8 tid;
+
+ ENTER();
+
+ eth = (struct ethhdr *) skb->data;
+
+ switch (eth->h_proto) {
+
+ case __constant_htons(ETH_P_IP):
+ tid = (IPTOS_PREC(SKB_TOS(skb)) >> IPTOS_OFFSET);
+ PRINTM(MDAT_D, "packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
+ eth->h_proto, tid, skb->priority);
+ break;
+
+ case __constant_htons(ETH_P_ARP):
+ PRINTM(MDATA, "ARP packet %04x\n", eth->h_proto);
+ tid = 0;
+ break;
+ default:
+ tid = 0;
+ break;
+ }
+
+ skb->priority = tid;
+
+ /* Record the current time the packet was queued; used to determine the
+ amount of time the packet was queued in the driver before it was sent to
+ the firmware. The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and MSDU lifetime
+ expiry. */
+ do_gettimeofday(&tstamp);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ skb->tstamp = timeval_to_ktime(tstamp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+ skb_set_timestamp(skb, &tstamp);
+#else
+ memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
+#endif
+
+ pmbuf->pdesc = skb;
+ pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
+ pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
+ pmbuf->data_len = skb->len;
+ pmbuf->priority = skb->priority;
+ pmbuf->buf_type = 0;
+ pmbuf->in_ts_sec = (t_u32) tstamp.tv_sec;
+ pmbuf->in_ts_usec = (t_u32) tstamp.tv_usec;
+
+ LEAVE();
+ return;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+static struct device_type wlan_type = {.name = "wlan", };
+#endif
+
+#ifdef STA_SUPPORT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+/** Network device handlers */
+const struct net_device_ops woal_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+ .ndo_set_rx_mode = woal_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_set_multicast_list,
+#endif
+ .ndo_select_queue = woal_select_queue,
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for station mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+woal_init_sta_dev(struct net_device *dev, moal_private * priv)
+{
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer);
+#ifdef WIRELESS_EXT
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers = (struct iw_handler_def *) &woal_handler_def;
+ }
+#endif
+#endif
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ /* Initialize private structure */
+ init_waitqueue_head(&priv->ioctl_wait_q);
+ init_waitqueue_head(&priv->cmd_wait_q);
+ init_waitqueue_head(&priv->proc_wait_q);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ init_waitqueue_head(&priv->w_stats_wait_q);
+#endif
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+/** Network device handlers */
+const struct net_device_ops woal_uap_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_uap_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+ .ndo_set_rx_mode = woal_uap_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_uap_set_multicast_list,
+#endif
+ .ndo_select_queue = woal_select_queue,
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for uap mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+woal_init_uap_dev(struct net_device *dev, moal_private * priv)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer);
+#ifdef UAP_WEXT
+#ifdef WIRELESS_EXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_uap_handler_def;
+ }
+#endif /* WIRELESS_EXT */
+#endif /* UAP_WEXT */
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ /* Initialize private structure */
+ init_waitqueue_head(&priv->ioctl_wait_q);
+ init_waitqueue_head(&priv->cmd_wait_q);
+ init_waitqueue_head(&priv->proc_wait_q);
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext))
+ init_waitqueue_head(&priv->w_stats_wait_q);
+#endif
+
+ LEAVE();
+ return status;
+}
+#endif /* UAP_SUPPORT */
+
+/**
+ * @brief This function adds a new interface. It will
+ * allocate, initialize and register the device.
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param bss_index BSS index number
+ * @param bss_type BSS type
+ *
+ * @return A pointer to the new priv structure
+ */
+moal_private *
+woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+
+ ENTER();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#define MAX_WMM_QUEUE 4
+ /* Allocate an Ethernet device */
+ if (!(dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE))) {
+#else
+ if (!(dev = alloc_etherdev(sizeof(moal_private)))) {
+#endif
+ PRINTM(MFATAL, "Init virtual ethernet device failed\n");
+ goto error;
+ }
+#ifdef STA_SUPPORT
+ /* Allocate device name */
+ if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, "wlan%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate mlan device name\n");
+ goto error;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if ((bss_type == MLAN_BSS_TYPE_UAP) && (dev_alloc_name(dev, "uap%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate uap device name\n");
+ goto error;
+ }
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+ if ((bss_type == MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (dev_alloc_name(dev, "wfd%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate wifidirect device name\n");
+ goto error;
+ }
+#endif
+ priv = (moal_private *) netdev_priv(dev);
+ /* Save the priv to handle */
+ handle->priv[bss_index] = priv;
+
+ /* Use the same handle structure */
+ priv->phandle = handle;
+ priv->netdev = dev;
+ priv->bss_index = bss_index;
+ priv->bss_type = bss_type;
+ if (bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+ else if (bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_role = MLAN_BSS_ROLE_UAP;
+#if defined(WIFI_DIRECT_SUPPORT)
+ else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+#endif
+
+ INIT_LIST_HEAD(&priv->tcp_sess_queue);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ SET_MODULE_OWNER(dev);
+#endif
+#ifdef STA_SUPPORT
+ if (bss_type == MLAN_BSS_TYPE_STA
+#if defined(WIFI_DIRECT_SUPPORT)
+ || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ )
+ woal_init_sta_dev(dev, priv);
+#endif
+#ifdef UAP_SUPPORT
+ if (bss_type == MLAN_BSS_TYPE_UAP) {
+ if (MLAN_STATUS_SUCCESS != woal_init_uap_dev(dev, priv))
+ goto error;
+ }
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if ((priv->bss_role == MLAN_BSS_ROLE_STA) && IS_STA_CFG80211(cfg80211_wext)) {
+ if (bss_type == MLAN_BSS_TYPE_STA
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+#endif
+ )
+ /* Register cfg80211 for STA or Wifi direct */
+ if (woal_register_sta_cfg80211(dev, bss_type)) {
+ PRINTM(MERROR, "Cannot register STA with cfg80211\n");
+ goto error;
+ }
+ }
+#endif /* STA_SUPPORT */
+#endif /* STA_CFG80211 */
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if ((priv->bss_role == MLAN_BSS_ROLE_UAP) && IS_UAP_CFG80211(cfg80211_wext)) {
+ /* Register cfg80211 for UAP */
+ if (woal_register_uap_cfg80211(dev, bss_type)) {
+ PRINTM(MERROR, "Cannot register UAP with cfg80211\n");
+ goto error;
+ }
+ }
+#endif
+#endif /* UAP_CFG80211 */
+
+ /* Initialize priv structure */
+ woal_init_priv(priv, MOAL_CMD_WAIT);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ SET_NETDEV_DEV(dev, handle->hotplug_device);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ SET_NETDEV_DEVTYPE(dev, &wlan_type);
+#endif
+
+ /* Register network device */
+ if (register_netdev(dev)) {
+ PRINTM(MERROR, "Cannot register virtual network device\n");
+ goto error;
+ }
+ netif_carrier_off(dev);
+ woal_stop_queue(dev);
+
+ PRINTM(MINFO, "%s: Marvell 802.11 Adapter\n", dev->name);
+
+ /* Set MAC address from the insmod command line */
+ if (handle->set_mac_addr) {
+ memset(priv->current_addr, 0, ETH_ALEN);
+ memcpy(priv->current_addr, handle->mac_addr, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ goto error;
+ }
+ memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+ }
+#ifdef CONFIG_PROC_FS
+ woal_create_proc_entry(priv);
+#ifdef PROC_DEBUG
+ woal_debug_entry(priv);
+#endif /* PROC_DEBUG */
+#endif /* CONFIG_PROC_FS */
+
+ LEAVE();
+ return priv;
+ error:
+ if (dev && dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+ /* Free wireless device */
+ kfree(priv->wdev);
+ priv->wdev = NULL;
+ }
+#endif
+ if (dev)
+ free_netdev(dev);
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes an interface.
+ *
+ * @param handle A pointer to the moal_handle structure
+ * @param bss_index BSS index number
+ *
+ * @return N/A
+ */
+void
+woal_remove_interface(moal_handle * handle, t_u8 bss_index)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = handle->priv[bss_index];
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ union iwreq_data wrqu;
+#endif
+
+ ENTER();
+ if (!priv)
+ goto error;
+ dev = priv->netdev;
+
+ if (priv->media_connected == MTRUE) {
+ priv->media_connected = MFALSE;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if (IS_STA_OR_UAP_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ }
+#ifdef CONFIG_PROC_FS
+#ifdef PROC_DEBUG
+ /* Remove proc debug */
+ woal_debug_remove(priv);
+#endif /* PROC_DEBUG */
+ woal_proc_remove(priv);
+#endif /* CONFIG_PROC_FS */
+ /* Last reference is our one */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+ PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+#else
+ PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev));
+#endif
+
+ PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name);
+
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+ /* Free wireless device */
+ kfree(priv->wdev);
+ priv->wdev = NULL;
+ }
+#endif
+
+ /* Clear the priv in handle */
+ priv->phandle->priv[priv->bss_index] = NULL;
+ priv->phandle = NULL;
+ priv->netdev = NULL;
+ free_netdev(dev);
+ error:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send FW shutdown command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_shutdown_fw(moal_private * priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN;
+ misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Return hex value of a give character
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted character if chr is a valid hex, else 0
+ */
+static int
+woal_hexval(char chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+#ifdef STA_WEXT
+#endif
+
+/**
+ * @brief This function cancel all works in the queue
+ * and destroy the main workqueue.
+ *
+ * @param handle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static void
+woal_terminate_workqueue(moal_handle * handle)
+{
+ ENTER();
+
+ /* Terminate main workqueue */
+ if (handle->workqueue) {
+ flush_workqueue(handle->workqueue);
+ destroy_workqueue(handle->workqueue);
+ handle->workqueue = NULL;
+ }
+
+ LEAVE();
+}
+
+/* Support for Cardhu wifi gpio toggling */
+/**
+ * @brief Sets the card detect state
+ *
+ * @param on 0: Card will be made undetected
+ * 1: Card will be detected
+ *
+ * @return 0
+ */
+static int
+wifi_set_carddetect(int on)
+{
+ ENTER();
+ PRINTM(MMSG, "%s = %d\n", __FUNCTION__, on);
+ if (wifi_control_data && wifi_control_data->set_carddetect) {
+ wifi_control_data->set_carddetect(on);
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Sets the power state to On or Off after 'msec' millisecond
+ *
+ * @param on 0: Card will be powered on
+ * 1: Card will be powered off
+ * @param msec Delay in millisecond
+ *
+ * @return 0
+ */
+static int
+wifi_set_power(int on, unsigned long msec)
+{
+ ENTER();
+ PRINTM(MMSG, "%s = %d\n", __FUNCTION__, on);
+ if (wifi_control_data && wifi_control_data->set_power) {
+ wifi_control_data->set_power(on);
+ }
+ if (msec)
+ mdelay(msec);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Probes an wifi device
+ *
+ * @param pdev A pointer to the platform_device structure
+ *
+ * @return 0
+ */
+static int
+wifi_probe(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *) (pdev->dev.platform_data);
+
+ ENTER();
+
+ wifi_control_data = wifi_ctrl;
+ wifi_set_power(1, 0); /* Power On */
+ wifi_set_carddetect(1); /* CardDetect (0->1) */
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Removes an wifi device
+ *
+ * @param pdev A pointer to the platform_device structure
+ *
+ * @return 0
+ */
+static int
+wifi_remove(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *) (pdev->dev.platform_data);
+
+ ENTER();
+
+ wifi_control_data = wifi_ctrl;
+ wifi_set_power(0, 0); /* Power Off */
+ wifi_set_carddetect(0); /* CardDetect (1->0) */
+
+ LEAVE();
+ return 0;
+}
+
+static struct platform_driver wifi_device = {
+ .probe = wifi_probe,
+ .remove = wifi_remove,
+ .driver = {
+ .name = "mrvl8797_wlan",
+ }
+};
+
+/**
+ * @brief Adds an wifi device
+ * @return 0 --success, otherwise fail
+ */
+static int
+wifi_add_dev(void)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (minicard_pwrup)
+ ret = platform_driver_register(&wifi_device);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Removes an wifi device
+ *
+ * @return N/A
+ */
+static void
+wifi_del_dev(void)
+{
+ ENTER();
+
+ if (minicard_pwrup)
+ platform_driver_unregister(&wifi_device);
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function opens the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_open(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u8 carrier_on = MFALSE;
+
+ ENTER();
+
+ if (!MODULE_GET) {
+ LEAVE();
+ return -EFAULT;
+ }
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) && (priv->media_connected))
+ carrier_on = MTRUE;
+#endif
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->media_connected || priv->is_adhoc_link_sensed))
+ carrier_on = MTRUE;
+#endif
+ if (carrier_on == MTRUE) {
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ } else {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function closes the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0
+ */
+int
+woal_close(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+#ifdef STA_SUPPORT
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, MTRUE);
+ priv->scan_request = NULL;
+ }
+#endif
+#endif
+ woal_stop_queue(priv->netdev);
+
+ MODULE_PUT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function sets the MAC address to firmware.
+ *
+ * @param dev A pointer to mlan_private structure
+ * @param addr MAC address to set
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct sockaddr *phw_addr = (struct sockaddr *) addr;
+ t_u8 prev_addr[ETH_ALEN];
+
+ ENTER();
+
+ memcpy(prev_addr, priv->current_addr, ETH_ALEN);
+ memset(priv->current_addr, 0, ETH_ALEN);
+ /* dev->dev_addr is 6 bytes */
+ HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+ HEXDUMP("addr:", (t_u8 *) phw_addr->sa_data, ETH_ALEN);
+ memcpy(priv->current_addr, phw_addr->sa_data, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ /* For failure restore the MAC address */
+ memcpy(priv->current_addr, prev_addr, ETH_ALEN);
+ ret = -EFAULT;
+ goto done;
+ }
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Display MLAN debug information
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return N/A
+ */
+void
+woal_mlan_debug_info(moal_private * priv)
+{
+ int i;
+
+ ENTER();
+
+ if (!priv || woal_get_debug_info(priv, MOAL_CMD_WAIT, &info)) {
+ PRINTM(MERROR, "Could not retrieve debug information from MLAN\n");
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MERROR, "num_cmd_timeout = %d\n", info.num_cmd_timeout);
+ PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x \n",
+ info.timeout_cmd_id, info.timeout_cmd_act);
+
+ PRINTM(MERROR, "last_cmd_index = %d\n", info.last_cmd_index);
+ PRINTM(MERROR, "last_cmd_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_cmd_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_act = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_cmd_act[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n", info.last_cmd_resp_index);
+ PRINTM(MERROR, "last_cmd_resp_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_cmd_resp_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_event_index = %d\n", info.last_event_index);
+ PRINTM(MERROR, "last_event = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_event[i]);
+ }
+ PRINTM(MERROR, "\n");
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ info.num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ info.num_cmd_host_to_card_failure);
+ PRINTM(MERROR, "num_data_c2h_failure = %d\n",
+ info.num_rx_card_to_host_failure);
+ PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
+ info.num_cmdevt_card_to_host_failure);
+ PRINTM(MERROR, "num_int_read_failure = %d\n", info.num_int_read_failure);
+ PRINTM(MERROR, "last_int_status = %d\n", info.last_int_status);
+
+ PRINTM(MERROR, "num_event_deauth = %d\n", info.num_event_deauth);
+ PRINTM(MERROR, "num_event_disassoc = %d\n", info.num_event_disassoc);
+ PRINTM(MERROR, "num_event_link_lost = %d\n", info.num_event_link_lost);
+ PRINTM(MERROR, "num_cmd_deauth = %d\n", info.num_cmd_deauth);
+ PRINTM(MERROR, "num_cmd_assoc_success = %d\n", info.num_cmd_assoc_success);
+ PRINTM(MERROR, "num_cmd_assoc_failure = %d\n", info.num_cmd_assoc_failure);
+ PRINTM(MERROR, "cmd_resp_received = %d\n", info.cmd_resp_received);
+ PRINTM(MERROR, "event_received = %d\n", info.event_received);
+
+ PRINTM(MERROR, "max_tx_buf_size = %d\n", info.max_tx_buf_size);
+ PRINTM(MERROR, "tx_buf_size = %d\n", info.tx_buf_size);
+ PRINTM(MERROR, "curr_tx_buf_size = %d\n", info.curr_tx_buf_size);
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", info.data_sent, info.cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", info.ps_mode, info.ps_state);
+ PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d\n",
+ info.pm_wakeup_card_req, info.pm_wakeup_fw_try);
+ PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
+ info.is_hs_configured, info.hs_activated);
+ PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n",
+ info.pps_uapsd_mode, info.sleep_pd);
+ PRINTM(MERROR, "tx_lock_flag = %d\n", info.tx_lock_flag);
+ PRINTM(MERROR, "port_open = %d\n", info.port_open);
+ PRINTM(MERROR, "scan_processing = %d\n", info.scan_processing);
+
+ PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ (unsigned int) info.mp_rd_bitmap, info.curr_rd_port);
+ PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ (unsigned int) info.mp_wr_bitmap, info.curr_wr_port);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the timeout of packet
+ * transmission
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void
+woal_tx_timeout(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ priv->num_tx_timeout++;
+ PRINTM(MERROR, "%lu : Tx timeout (%d), bss_index=%d\n",
+ jiffies, priv->num_tx_timeout, priv->bss_index);
+ woal_set_trans_start(dev);
+
+ if (priv->num_tx_timeout == NUM_TX_TIMEOUT_THRESHOLD) {
+ woal_mlan_debug_info(priv);
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to net_device_stats structure
+ */
+struct net_device_stats *
+woal_get_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ return &priv->stats;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+/**
+ * @brief This function handles wmm queue select
+ *
+ * @param dev A pointer to net_device structure
+ * @param skb A pointer to sk_buff structure
+ *
+ * @return tx_queue index (0-3)
+ */
+u16
+woal_select_queue(struct net_device * dev, struct sk_buff * skb)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct ethhdr *eth = NULL;
+ struct iphdr *iph;
+ t_u8 tid = 0;
+ t_u8 index = 0;
+
+ ENTER();
+
+ eth = (struct ethhdr *) skb->data;
+ switch (eth->h_proto) {
+ case __constant_htons(ETH_P_IP):
+ iph = ip_hdr(skb);
+ tid = IPTOS_PREC(iph->tos);
+ break;
+ case __constant_htons(ETH_P_ARP):
+ default:
+ break;
+ }
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+ tid = (tid >> IPTOS_OFFSET);
+ index =
+ mlan_select_wmm_queue(priv->phandle->pmlan_adapter, priv->bss_index,
+ tid);
+ PRINTM(MDATA, "select queue: tid=%d, index=%d\n", tid, index);
+ LEAVE();
+ return index;
+}
+#endif
+
+/**
+ * @brief This function gets tcp session from the tcp session queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param src_ip IP address of the device
+ * @param src_port TCP port of the device
+ * @param dst_ip IP address of the client
+ * @param src_port TCP port of the client
+ *
+ * @return A pointer to the tcp session data structure, if found.
+ * Otherwise, null
+ */
+struct tcp_sess *
+woal_get_tcp_sess(moal_private * priv,
+ t_u32 src_ip, t_u16 src_port, t_u32 dst_ip, t_u16 dst_port)
+{
+ struct tcp_sess *tcp_sess = NULL;
+ ENTER();
+
+ list_for_each_entry(tcp_sess, &priv->tcp_sess_queue, link) {
+ if ((tcp_sess->src_ip_addr == src_ip) &&
+ (tcp_sess->src_tcp_port == src_port) &&
+ (tcp_sess->dst_ip_addr == dst_ip) &&
+ (tcp_sess->dst_tcp_port == dst_port)) {
+ LEAVE();
+ return tcp_sess;
+ }
+ }
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function checks received tcp packet for FIN
+ * and release the tcp session if received
+ *
+ * @param priv A pointer to moal_private structure
+ * @param skb A pointer to sk_buff structure
+ *
+ * @return None
+ */
+void
+woal_check_tcp_fin(moal_private * priv, struct sk_buff *skb)
+{
+ struct ethhdr *ethh = NULL;
+ struct iphdr *iph = NULL;
+ struct tcphdr *tcph = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+
+ ENTER();
+
+ ethh = eth_hdr(skb);
+ if (ntohs(ethh->h_proto) == ETH_P_IP) {
+ iph = (struct iphdr *) ((t_u8 *) ethh + sizeof(struct ethhdr));
+ if (iph->protocol == IPPROTO_TCP) {
+ tcph = (struct tcphdr *) ((t_u8 *) iph + iph->ihl * 4);
+ if (tcph->fin) {
+ tcp_sess = woal_get_tcp_sess(priv, iph->daddr,
+ tcph->dest, iph->saddr,
+ tcph->source);
+ if (tcp_sess != NULL) {
+ PRINTM(MINFO,
+ "TX: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ iph->daddr, tcph->dest, iph->saddr, tcph->source);
+ /* remove the tcp session from the queue */
+ list_del(&tcp_sess->link);
+ kfree(tcp_sess);
+ } else {
+ PRINTM(MINFO, "Tx: released TCP session is not found.\n ");
+ }
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function process tcp ack packets
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pmbuf A pointer to the mlan buffer associated with the skb
+ *
+ * @return 1, if a tcp ack packet has been dropped. Otherwise, 0.
+ */
+int
+woal_process_tcp_ack(moal_private * priv, mlan_buffer * pmbuf)
+{
+ int ret = 0;
+ struct ethhdr *ethh = NULL;
+ struct iphdr *iph = NULL;
+ struct tcphdr *tcph = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+ struct sk_buff *skb = NULL;
+ t_u32 ack_seq = 0;
+ t_u32 len = 0;
+ t_u8 opt = 0;
+ t_u8 opt_len = 0;
+ t_u8 *pos = NULL;
+ t_u32 win_size = 0;
+
+#define TCP_ACK_DELAY 3
+#define TCP_ACK_INIT_WARMING_UP 1000 /* initial */
+#define TCP_ACK_RECV_WARMING_UP 1000 /* recovery */
+
+ ENTER();
+
+ /** check the tcp packet */
+ ethh = (struct ethhdr *) (pmbuf->pbuf + pmbuf->data_offset);
+ if (ntohs(ethh->h_proto) != ETH_P_IP) {
+ return 0;
+ }
+ iph = (struct iphdr *) ((t_u8 *) ethh + sizeof(struct ethhdr));
+ if (iph->protocol != IPPROTO_TCP) {
+ return 0;
+ }
+ tcph = (struct tcphdr *) ((t_u8 *) iph + iph->ihl * 4);
+
+ if (tcph->syn & tcph->ack) {
+ /* respond to a TCP request. create a tcp session */
+ if (!(tcp_sess = kmalloc(sizeof(struct tcp_sess), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Fail to allocate tcp_sess.\n");
+ return 0;
+ }
+ memset(tcp_sess, 0, sizeof(struct tcp_sess));
+ tcp_sess->src_ip_addr = iph->saddr; /* my ip addr */
+ tcp_sess->dst_ip_addr = iph->daddr;
+ tcp_sess->src_tcp_port = tcph->source;
+ tcp_sess->dst_tcp_port = tcph->dest;
+ tcp_sess->start_cnt = TCP_ACK_INIT_WARMING_UP;
+
+ INIT_LIST_HEAD(&tcp_sess->link);
+ list_add_tail(&tcp_sess->link, &priv->tcp_sess_queue);
+ PRINTM(MINFO,
+ "create a tcp session. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ iph->saddr, tcph->source, iph->daddr, tcph->dest);
+
+ /* parse tcp options for the window scale */
+ len = (tcph->doff * 4) - sizeof(struct tcphdr);
+ pos = (t_u8 *) (tcph + 1);
+ while (len > 0) {
+ opt = *pos++;
+ switch (opt) {
+ case TCPOPT_EOL:
+ len = 0;
+ continue;
+ case TCPOPT_NOP:
+ len--;
+ continue;
+ case TCPOPT_WINDOW:
+ opt_len = *pos++;
+ if (opt_len == TCPOLEN_WINDOW) {
+ tcp_sess->rx_win_scale = *pos;
+ tcp_sess->rx_win_opt = 1;
+ if (tcp_sess->rx_win_scale > 14)
+ tcp_sess->rx_win_scale = 14;
+ PRINTM(MINFO, "TCP Window Scale: %d \n",
+ tcp_sess->rx_win_scale);
+ }
+ break;
+ default:
+ opt_len = *pos++;
+ }
+ len -= opt_len;
+ pos += opt_len - 2;
+ }
+ } else if (tcph->ack && !(tcph->syn) &&
+ (ntohs(iph->tot_len) == (iph->ihl * 4 + tcph->doff * 4))) {
+ /** it is an ack packet, not a piggyback ack */
+ tcp_sess = woal_get_tcp_sess(priv, iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ if (tcp_sess == NULL) {
+ return 0;
+ }
+ /** do not drop the ack packets initially */
+ if (tcp_sess->start_cnt) {
+ tcp_sess->start_cnt--;
+ return 0;
+ }
+
+ /* check the window size. */
+ win_size = ntohs(tcph->window);
+ if (tcp_sess->rx_win_opt) {
+ win_size <<= tcp_sess->rx_win_scale;
+ /* Note: it may depend on the rtd */
+ if ((win_size > 1500 * (TCP_ACK_DELAY + 5)) &&
+ (tcp_sess->ack_cnt < TCP_ACK_DELAY)) {
+ /* if windiow is big enough, drop the ack packet */
+ if (tcp_sess->ack_seq != ntohl(tcph->ack_seq)) {
+ ack_seq = tcp_sess->ack_seq;
+ tcp_sess->ack_seq = ntohl(tcph->ack_seq);
+ tcp_sess->ack_cnt++;
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (skb)
+ dev_kfree_skb_any(skb);
+ ret = 1;
+ } else {
+ /* the ack packet is retransmitted. thus, stop dropping
+ the ack packets */
+ tcp_sess->start_cnt = TCP_ACK_RECV_WARMING_UP;
+ PRINTM(MINFO, "Recover the TCP session.\n ");
+ }
+ } else {
+ /* send the current ack pacekt */
+ ack_seq = tcp_sess->ack_seq;
+ tcp_sess->ack_seq = ntohl(tcph->ack_seq);
+ tcp_sess->ack_cnt = 0;
+ ret = 0;
+ }
+ }
+ } else if (tcph->fin) {
+ tcp_sess = woal_get_tcp_sess(priv, iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ if (tcp_sess != NULL) {
+ /* remove the tcp session from the queue */
+ PRINTM(MINFO,
+ "Rx: release a tcp session in ul. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ iph->saddr, tcph->source, iph->daddr, tcph->dest);
+ list_del(&tcp_sess->link);
+ kfree(tcp_sess);
+ } else {
+ PRINTM(MINFO, "released TCP session is not found.\n ");
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles packet transmission
+ *
+ * @param skb A pointer to sk_buff structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success
+ */
+int
+woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_buffer *pmbuf = NULL;
+ mlan_status status;
+ struct sk_buff *new_skb = NULL;
+
+ ENTER();
+
+ PRINTM(MDATA, "%lu BSS(%d): Data <= kernel\n", jiffies, priv->bss_index);
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ priv->num_tx_timeout = 0;
+ if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+ PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n",
+ skb->len, ETH_FRAME_LEN);
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (skb->cloned ||
+ (skb_headroom(skb) <
+ (MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)))) {
+ PRINTM(MWARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb =
+ skb_realloc_headroom(skb,
+ MLAN_MIN_DATA_HEADER_LEN +
+ sizeof(mlan_buffer));
+ if (unlikely(!new_skb)) {
+ PRINTM(MERROR, "Tx: Cannot allocate skb\n");
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (new_skb != skb)
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb));
+ }
+ pmbuf = (mlan_buffer *) skb->head;
+ memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer));
+ pmbuf->bss_index = priv->bss_index;
+ woal_fill_mlan_buffer(priv, pmbuf, skb);
+ if (priv->enable_tcp_ack_enh == MTRUE) {
+ if (woal_process_tcp_ack(priv, pmbuf)) {
+ /* the ack packet has been dropped */
+ goto done;
+ }
+ }
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
+ woal_stop_queue(priv->netdev);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ dev_kfree_skb_any(skb);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Convert ascii string to Hex integer
+ *
+ * @param d A pointer to integer buf
+ * @param s A pointer to ascii string
+ * @param dlen The byte number of ascii string in hex
+ *
+ * @return Number of integer
+ */
+int
+woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen)
+{
+ unsigned int i;
+ t_u8 n;
+
+ ENTER();
+
+ memset(d, 0x00, dlen);
+
+ for (i = 0; i < dlen * 2; i++) {
+ if ((s[i] >= 48) && (s[i] <= 57))
+ n = s[i] - 48;
+ else if ((s[i] >= 65) && (s[i] <= 70))
+ n = s[i] - 55;
+ else if ((s[i] >= 97) && (s[i] <= 102))
+ n = s[i] - 87;
+ else
+ break;
+ if (!(i % 2))
+ n = n * 16;
+ d[i / 2] += n;
+ }
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Return integer value of a given ascii string
+ *
+ * @param data Converted data to be returned
+ * @param a String to be converted
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_atoi(int *data, char *a)
+{
+ int i, val = 0, len;
+
+ ENTER();
+
+ len = strlen(a);
+ if (!strncmp(a, "0x", 2)) {
+ a = a + 2;
+ len -= 2;
+ *data = woal_atox(a);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ for (i = 0; i < len; i++) {
+ if (isdigit(a[i])) {
+ val = val * 10 + (a[i] - '0');
+ } else {
+ PRINTM(MERROR, "Invalid char %c in string %s\n", a[i], a);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ *data = val;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Return hex value of a given ascii string
+ *
+ * @param a String to be converted to ascii
+ *
+ * @return The converted character if a is a valid hex, else 0
+ */
+int
+woal_atox(char *a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (isxdigit(*a))
+ i = i * 16 + woal_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Extension of strsep lib command. This function will also take care
+ * escape character
+ *
+ * @param s A pointer to array of chars to process
+ * @param delim The delimiter character to end the string
+ * @param esc The escape character to ignore for delimiter
+ *
+ * @return Pointer to the separated string if delim found, else NULL
+ */
+char *
+woal_strsep(char **s, char delim, char esc)
+{
+ char *se = *s, *sb;
+
+ ENTER();
+
+ if (!(*s) || (*se == '\0')) {
+ LEAVE();
+ return NULL;
+ }
+
+ for (sb = *s; *sb != '\0'; ++sb) {
+ if (*sb == esc && *(sb + 1) == esc) {
+ /*
+ * We get a esc + esc seq then keep the one esc
+ * and chop off the other esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == esc && *(sb + 1) == delim) {
+ /*
+ * We get a delim + esc seq then keep the delim
+ * and chop off the esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == delim)
+ break;
+ }
+
+ if (*sb == '\0')
+ sb = NULL;
+ else
+ *sb++ = '\0';
+
+ *s = sb;
+
+ LEAVE();
+ return se;
+}
+
+/**
+ * @brief Convert mac address from string to t_u8 buffer.
+ *
+ * @param mac_addr The buffer to store the mac address in.
+ * @param buf The source of mac address which is a string.
+ *
+ * @return N/A
+ */
+void
+woal_mac2u8(t_u8 * mac_addr, char *buf)
+{
+ char *begin = buf, *end;
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < ETH_ALEN; ++i) {
+ end = woal_strsep(&begin, ':', '/');
+ if (end)
+ mac_addr[i] = woal_atox(end);
+ }
+
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void
+woal_set_multicast_list(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ woal_request_set_multicast_list(priv, dev);
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and set default value to the member of moal_private.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+void
+woal_init_priv(moal_private * priv, t_u8 wait_option)
+{
+ struct list_head *link = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+ ENTER();
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->current_key_index = 0;
+ priv->rate_index = AUTO_RATE;
+ priv->is_adhoc_link_sensed = MFALSE;
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ priv->num_tx_timeout = 0;
+ priv->rx_filter = 0;
+
+#ifdef REASSOCIATION
+ priv->reassoc_on = MFALSE;
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (priv->bss_type == MLAN_BSS_TYPE_STA
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+#endif
+ )
+ woal_cfg80211_sta_init_wiphy(priv, wait_option);
+ }
+#endif
+ }
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ priv->bss_started = MFALSE;
+#ifdef UAP_CFG80211
+ if (IS_UAP_CFG80211(cfg80211_wext))
+ woal_cfg80211_uap_init_wiphy(priv, wait_option);
+#endif
+ }
+#endif
+ priv->media_connected = MFALSE;
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+#endif
+#ifdef STA_SUPPORT
+#endif
+
+ priv->enable_tcp_ack_enh = MTRUE;
+ while (!list_empty(&priv->tcp_sess_queue)) {
+ link = priv->tcp_sess_queue.next;
+ tcp_sess = list_entry(link, struct tcp_sess, link);
+ PRINTM(MINFO,
+ "warm reset: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ tcp_sess->src_ip_addr, tcp_sess->src_tcp_port,
+ tcp_sess->dst_ip_addr, tcp_sess->dst_tcp_port);
+ list_del(link);
+ kfree(tcp_sess);
+ }
+
+ woal_request_get_fw_info(priv, wait_option, NULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief Reset all interfaces if all_intf flag is TRUE,
+ * otherwise specified interface only
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param all_intf TRUE : all interfaces
+ * FALSE : current interface only
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ int intf_num;
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ /* Stop queue and detach device */
+ if (!all_intf) {
+ woal_stop_queue(priv->netdev);
+ netif_device_detach(priv->netdev);
+ } else {
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_stop_queue(handle->priv[intf_num]->netdev);
+ netif_device_detach(handle->priv[intf_num]->netdev);
+ }
+ }
+
+ /* Get BSS info */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, wait_option, &bss_info);
+
+#ifdef STA_SUPPORT
+ /* If scan is in process, cancel the scan command */
+ if (handle->scan_pending_on_block == MTRUE) {
+ mlan_ioctl_req *req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -EFAULT;
+ goto err_cancel_scan;
+ }
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ ((mlan_ds_scan *) req->pbuf)->sub_command = MLAN_OID_SCAN_CANCEL;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = -EFAULT;
+ goto err_cancel_scan;
+ }
+ err_cancel_scan:
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ if (req)
+ kfree(req);
+ }
+#endif
+
+ /* Cancel host sleep */
+ if (bss_info.is_hs_configured) {
+ if (MLAN_STATUS_SUCCESS != woal_cancel_hs(priv, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect from network */
+ if (!all_intf) {
+ /* Disconnect specified interface only */
+ if ((priv->media_connected == MTRUE)
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ woal_disconnect(priv, wait_option, NULL);
+ priv->media_connected = MFALSE;
+ }
+ } else {
+ /* Disconnect all interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ if (handle->priv[intf_num]->media_connected == MTRUE
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(handle->priv[intf_num]) == MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ woal_disconnect(handle->priv[intf_num], wait_option, NULL);
+ handle->priv[intf_num]->media_connected = MFALSE;
+ }
+ }
+ }
+
+#ifdef REASSOCIATION
+ /* Reset the reassoc timer and status */
+ if (!all_intf) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ } else {
+ handle->reassoc_on = 0;
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ handle->priv[intf_num]->reassoc_on = MFALSE;
+ }
+ }
+ if (!handle->reassoc_on && handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+#endif /* REASSOCIATION */
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function return the point to structure moal_private
+ *
+ * @param handle Pointer to structure moal_handle
+ * @param bss_index BSS index number
+ *
+ * @return moal_private pointer or NULL
+ */
+moal_private *
+woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index)
+{
+ int i;
+
+ ENTER();
+ if (!handle) {
+ LEAVE();
+ return NULL;
+ }
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (handle->priv[i] && (handle->priv[i]->bss_index == bss_index)) {
+ LEAVE();
+ return handle->priv[i];
+ }
+ }
+
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function alloc mlan_buffer.
+ * @param handle A pointer to moal_handle structure
+ * @param size buffer size to allocate
+ *
+ * @return mlan_buffer pointer or NULL
+ */
+pmlan_buffer
+woal_alloc_mlan_buffer(moal_handle * handle, int size)
+{
+ mlan_buffer *pmbuf = NULL;
+ struct sk_buff *skb;
+
+ ENTER();
+ if (!(pmbuf = kmalloc(sizeof(mlan_buffer), GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: Fail to alloc mlan buffer\n", __FUNCTION__);
+ LEAVE();
+ return NULL;
+ }
+ memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer));
+ if (!(skb = dev_alloc_skb(size))) {
+ PRINTM(MERROR, "%s: No free skb\n", __FUNCTION__);
+ kfree(pmbuf);
+ LEAVE();
+ return NULL;
+ }
+ pmbuf->pdesc = (t_void *) skb;
+ pmbuf->pbuf = (t_u8 *) skb->data;
+ handle->mbufalloc_count++;
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function alloc mlan_ioctl_req.
+ *
+ * @param size buffer size to allocate
+ *
+ * @return mlan_ioctl_req pointer or NULL
+ */
+pmlan_ioctl_req
+woal_alloc_mlan_ioctl_req(int size)
+{
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (!
+ (req =
+ (mlan_ioctl_req *)
+ kmalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) +
+ sizeof(wait_queue)), GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: Fail to alloc ioctl buffer\n", __FUNCTION__);
+ LEAVE();
+ return NULL;
+ }
+ memset((t_u8 *) req, 0, (sizeof(mlan_ioctl_req) + size +
+ sizeof(int) + sizeof(wait_queue)));
+ req->pbuf = (t_u8 *) req + sizeof(mlan_ioctl_req) + sizeof(wait_queue);
+ req->buf_len = (t_u32) size;
+ req->reserved_1 = (t_ptr) ((t_u8 *) req + sizeof(mlan_ioctl_req));
+
+ LEAVE();
+ return req;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ * @param handle A pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+void
+woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf)
+{
+ ENTER();
+ if (!pmbuf) {
+ LEAVE();
+ return;
+ }
+ if (pmbuf->pdesc)
+ dev_kfree_skb_any((struct sk_buff *) pmbuf->pdesc);
+ kfree(pmbuf);
+ handle->mbufalloc_count--;
+ LEAVE();
+ return;
+}
+
+#ifdef STA_WEXT
+#endif
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param payload A pointer to payload buffer
+ * @param len Length of the payload
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_broadcast_event(moal_private * priv, t_u8 * payload, t_u32 len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ moal_handle *handle = priv->phandle;
+ struct sock *sk = handle->nl_sk;
+
+ ENTER();
+ /* interface name to be prepended to event */
+ if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD) {
+ PRINTM(MERROR, "event size is too big, len=%d\n", (int) len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (sk) {
+ /* Allocate skb */
+ if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Could not allocate skb for netlink\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ nlh = (struct nlmsghdr *) skb->data;
+ nlh->nlmsg_len = NLMSG_SPACE(len + IFNAMSIZ);
+
+ /* From kernel */
+ nlh->nlmsg_pid = 0;
+ nlh->nlmsg_flags = 0;
+
+ /* Data */
+ skb_put(skb, nlh->nlmsg_len);
+ memcpy(NLMSG_DATA(nlh), priv->netdev->name, IFNAMSIZ);
+ memcpy(((t_u8 *) (NLMSG_DATA(nlh))) + IFNAMSIZ, payload, len);
+
+ /* From Kernel */
+ NETLINK_CB(skb).pid = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ /* Multicast message */
+ NETLINK_CB(skb).dst_pid = 0;
+#endif
+
+ /* Multicast group number */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ NETLINK_CB(skb).dst_groups = NL_MULTICAST_GROUP;
+#else
+ NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
+#endif
+
+ /* Send message */
+ netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP, GFP_ATOMIC);
+
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR, "Could not send event through NETLINK. Link down.\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef REASSOCIATION
+/**
+ * @brief This function handles re-association. it is triggered
+ * by re-assoc timer.
+ *
+ * @param data A pointer to wlan_thread structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+woal_reassociation_thread(void *data)
+{
+ moal_thread *pmoal_thread = data;
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_thread->handle;
+ wait_queue_t wait;
+ int i;
+ BOOLEAN reassoc_timer_req;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_status status;
+ mlan_bss_info bss_info;
+ t_u32 timer_val = MOAL_TIMER_10S;
+
+ ENTER();
+
+ woal_activate_thread(pmoal_thread);
+ init_waitqueue_entry(&wait, current);
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&pmoal_thread->wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&pmoal_thread->wait_q, &wait);
+
+ /* Cancel re-association timer */
+ if (handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+
+ if (handle->surprise_removed)
+ break;
+ if (kthread_should_stop())
+ break;
+
+ if (handle->hardware_status != HardwareStatusReady) {
+ PRINTM(MINFO, "Reassoc: Hardware status is not correct\n");
+ continue;
+ }
+
+ PRINTM(MEVENT, "Reassoc: Thread waking up...\n");
+ reassoc_timer_req = MFALSE;
+
+ for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) {
+
+ if (priv->reassoc_required == MFALSE) {
+ continue;
+ }
+
+ memset(&bss_info, 0x00, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_CMD_WAIT,
+ &bss_info)) {
+ PRINTM(MINFO, "Ressoc: Fail to get bss info\n");
+ priv->reassoc_required = MFALSE;
+ continue;
+ }
+
+ if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA ||
+ priv->media_connected != MFALSE) {
+ PRINTM(MINFO, "Reassoc: ad-hoc mode or media connected\n");
+ priv->reassoc_required = MFALSE;
+ continue;
+ }
+
+ /* The semaphore is used to avoid reassociation thread and
+ wlan_set_scan/wlan_set_essid interrupting each other.
+ Reassociation should be disabled completely by application if
+ wlan_set_user_scan_ioctl/wlan_set_wap is used. */
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR,
+ "Acquire semaphore error, reassociation thread\n");
+ reassoc_timer_req = MTRUE;
+ break;
+ }
+
+ PRINTM(MINFO, "Reassoc: Required ESSID: %s\n",
+ priv->prev_ssid_bssid.ssid.ssid);
+ PRINTM(MINFO, "Reassoc: Performing Active Scan\n");
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+ memcpy(&req_ssid,
+ &priv->prev_ssid_bssid.ssid, sizeof(mlan_802_11_ssid));
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_CMD_WAIT, &req_ssid)) {
+ PRINTM(MERROR, "Reassoc: Fail to do specific scan\n");
+ reassoc_timer_req = MTRUE;
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ if (handle->surprise_removed) {
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ /* Search AP by BSSID first */
+ PRINTM(MINFO, "Reassoc: Search AP by BSSID first\n");
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&ssid_bssid.bssid,
+ &priv->prev_ssid_bssid.bssid, MLAN_MAC_ADDR_LENGTH);
+ status = woal_find_best_network(priv, MOAL_CMD_WAIT, &ssid_bssid);
+
+ if (MLAN_STATUS_SUCCESS != status) {
+ PRINTM(MINFO, "Reassoc: AP not found in scan list\n");
+ PRINTM(MINFO, "Reassoc: Search AP by SSID\n");
+ /* Search AP by SSID */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&ssid_bssid.ssid,
+ &priv->prev_ssid_bssid.ssid, sizeof(mlan_802_11_ssid));
+ status = woal_find_best_network(priv,
+ MOAL_CMD_WAIT, &ssid_bssid);
+ }
+
+ if (status == MLAN_STATUS_SUCCESS) {
+ /* set the wep key */
+ if (bss_info.wep_status)
+ woal_enable_wep_key(priv, MOAL_CMD_WAIT);
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ status = woal_bss_start(priv, MOAL_CMD_WAIT, &ssid_bssid);
+ }
+
+ if (priv->media_connected == MFALSE)
+ reassoc_timer_req = MTRUE;
+ else {
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ reassoc_timer_req = MFALSE;
+ if (priv->rate_index != AUTO_RATE) {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+
+ req->action = MLAN_ACT_SET;
+
+ rate->param.rate_cfg.rate = priv->rate_index;
+
+ if (MLAN_STATUS_SUCCESS
+ != woal_request_ioctl(priv, req, MOAL_CMD_WAIT)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (req)
+ kfree(req);
+ }
+ }
+
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ }
+
+ if (handle->surprise_removed)
+ break;
+
+ if (reassoc_timer_req == MTRUE) {
+ handle->is_reassoc_timer_set = MTRUE;
+ {
+ PRINTM(MEVENT,
+ "Reassoc: No AP found or assoc failed. "
+ "Restarting re-assoc Timer: %d\n", (int) timer_val);
+ woal_mod_timer(&handle->reassoc_timer, timer_val);
+ }
+ }
+ }
+ woal_deactivate_thread(pmoal_thread);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function triggers re-association by waking up
+ * re-assoc thread.
+ *
+ * @param context A pointer to context
+ * @return N/A
+ */
+void
+woal_reassoc_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *) context;
+
+ ENTER();
+
+ PRINTM(MINFO, "reassoc_timer fired.\n");
+ handle->is_reassoc_timer_set = MFALSE;
+
+ PRINTM(MINFO, "Waking Up the Reassoc Thread\n");
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ LEAVE();
+ return;
+}
+#endif /* REASSOCIATION */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Sends disconnect event
+ *
+ * @param priv A pointer to moal_private struct
+ * @return N/A
+ */
+t_void
+woal_send_disconnect_to_system(moal_private * priv)
+{
+#ifdef STA_WEXT
+ union iwreq_data wrqu;
+#endif
+
+ ENTER();
+ priv->media_connected = MFALSE;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ LEAVE();
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function reads and displays SDIO registers for debugging
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void
+woal_sdio_reg_dbg(moal_handle * phandle)
+{
+ int ret = 0;
+ t_u8 loop, index = 0, func, data;
+ unsigned int reg, reg_start, reg_end;
+ unsigned int reg_table[] = { 0x28, 0x30, 0x34, 0x38, 0x3c };
+ char buf[128], *ptr;
+
+ sdio_claim_host(((struct sdio_mmc_card *) phandle->card)->func);
+ for (loop = 0; loop < 5; loop++) {
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ if (loop < 2) {
+ /* Read the registers of SDIO function0 and function1 */
+ func = loop;
+ reg_start = 0;
+ reg_end = 9;
+ } else if (loop == 2) {
+ /* Read specific registers of SDIO function1 */
+ index = 0;
+ func = 1;
+ reg_start = reg_table[index++];
+ reg_end = reg_table[sizeof(reg_table) / sizeof(int) - 1];
+ } else {
+ /* Read the scratch registers of SDIO function1 */
+ if (loop == 4)
+ mdelay(100);
+ func = 1;
+#define SDIO_SCRATCH_REG 0x60
+ reg_start = SDIO_SCRATCH_REG;
+ reg_end = SDIO_SCRATCH_REG + 10;
+ }
+ if (loop != 2)
+ ptr +=
+ sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func, reg_start,
+ reg_end);
+ else
+ ptr += sprintf(ptr, "SDIO Func%d: ", func);
+ for (reg = reg_start; reg <= reg_end;) {
+ if (func == 0)
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) phandle->card)->
+ func, reg, &ret);
+ else
+ data =
+ sdio_readb(((struct sdio_mmc_card *) phandle->card)->func,
+ reg, &ret);
+ if (loop == 2)
+ ptr += sprintf(ptr, "(%#x) ", reg);
+ if (!ret)
+ ptr += sprintf(ptr, "%02x ", data);
+ else {
+ ptr += sprintf(ptr, "ERR");
+ break;
+ }
+ if (loop == 2 && reg < reg_end)
+ reg = reg_table[index++];
+ else
+ reg++;
+ }
+ PRINTM(MMSG, "%s\n", buf);
+ }
+ sdio_release_host(((struct sdio_mmc_card *) phandle->card)->func);
+}
+
+/**
+ * @brief This function displays extra MOAL debug information
+ *
+ * @param priv A pointer to moal_private
+ * @param handle A pointer to moal_handle
+ * @param flag Indicates whether register read can be done directly
+ *
+ * @return N/A
+ */
+void
+woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag)
+{
+ moal_handle *phandle = NULL;
+ char buf[MLAN_MAX_VER_STR_LEN];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ int i = 0;
+#endif
+
+ ENTER();
+
+ if (!priv) {
+ if (handle) {
+ phandle = handle;
+ } else {
+ PRINTM(MERROR, "Could not retrieve debug information from MOAL\n");
+ LEAVE();
+ return;
+ }
+ } else {
+ phandle = priv->phandle;
+ }
+
+ woal_get_version(phandle, buf, sizeof(buf) - 1);
+ PRINTM(MERROR, "Driver version = %s\n", buf);
+ PRINTM(MERROR, "main_state = %d\n", phandle->main_state);
+ PRINTM(MERROR, "ioctl_pending = %d\n",
+ atomic_read(&phandle->ioctl_pending));
+ PRINTM(MERROR, "tx_pending = %d\n", atomic_read(&phandle->tx_pending));
+ PRINTM(MERROR, "rx_pending = %d\n", atomic_read(&phandle->rx_pending));
+ PRINTM(MERROR, "malloc_count = %u\n", phandle->malloc_count);
+ PRINTM(MERROR, "lock_count = %u\n", phandle->lock_count);
+ PRINTM(MERROR, "mbufalloc_count = %u\n", phandle->mbufalloc_count);
+#if defined(SDIO_SUSPEND_RESUME)
+ PRINTM(MERROR, "hs_skip_count = %u\n", phandle->hs_skip_count);
+ PRINTM(MERROR, "hs_force_count = %u\n", phandle->hs_force_count);
+#endif
+
+ if (priv) {
+ PRINTM(MERROR, "Media state = \"%s\"\n",
+ ((priv->media_connected ==
+ MFALSE) ? "Disconnected" : "Connected"));
+ PRINTM(MERROR, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
+ PRINTM(MERROR, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped
+ (netdev_get_tx_queue(priv->netdev, 0))) ? "stopped" :
+ "started"));
+ }
+#else
+ PRINTM(MERROR, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started"));
+#endif
+ }
+
+ /* Display SDIO registers */
+ if (flag && phandle->main_state == MOAL_END_MAIN_PROCESS) {
+ woal_sdio_reg_dbg(phandle);
+ } else {
+ phandle->sdio_reg_dbg = MTRUE;
+ queue_work(phandle->workqueue, &phandle->main_work);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This workqueue function handles main_process
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void
+woal_main_work_queue(struct work_struct * work)
+{
+ moal_handle *handle = container_of(work, moal_handle, main_work);
+
+ ENTER();
+
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ if (handle->sdio_reg_dbg == MTRUE) {
+ handle->sdio_reg_dbg = MFALSE;
+ woal_sdio_reg_dbg(handle);
+ LEAVE();
+ return;
+ }
+
+ handle->main_state = MOAL_ENTER_WORK_QUEUE;
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ handle->main_state = MOAL_START_MAIN_PROCESS;
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ handle->main_state = MOAL_END_MAIN_PROCESS;
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ LEAVE();
+}
+
+/**
+ * @brief Handles interrupt
+ *
+ * @param handle A pointer to moal_handle struct
+ *
+ * @return N/A
+ */
+void
+woal_interrupt(moal_handle * handle)
+{
+ ENTER();
+ handle->main_state = MOAL_RECV_INT;
+ PRINTM(MINTR, "*\n");
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ /* call mlan_interrupt to read int status */
+ mlan_interrupt(handle->pmlan_adapter);
+ handle->main_state = MOAL_START_MAIN_PROCESS;
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ handle->main_state = MOAL_END_MAIN_PROCESS;
+ LEAVE();
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the mlan_private and initialize the device.
+ *
+ * @param card A pointer to card
+ *
+ * @return A pointer to moal_handle structure
+ */
+moal_handle *
+woal_add_card(void *card)
+{
+ moal_handle *handle = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int netlink_num = NETLINK_MARVELL;
+ int index = 0;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ /* Allocate buffer for moal_handle */
+ if (!(handle = kmalloc(sizeof(moal_handle), GFP_KERNEL))) {
+ PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
+ goto err_handle;
+ }
+
+ /* Init moal_handle */
+ memset(handle, 0, sizeof(moal_handle));
+ handle->card = card;
+ /* Save the handle */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == NULL)
+ break;
+ }
+ if (index < MAX_MLAN_ADAPTER) {
+ m_handle[index] = handle;
+ handle->handle_idx = index;
+ } else {
+ PRINTM(MERROR, "Exceeded maximum cards supported!\n");
+ goto err_kmalloc;
+ }
+
+ if (mac_addr) {
+ t_u8 temp[20];
+ t_u8 len = strlen(mac_addr) + 1;
+ if (len < sizeof(temp)) {
+ memcpy(temp, mac_addr, len);
+ handle->set_mac_addr = 1;
+ /* note: the following function overwrites the temp buffer */
+ woal_mac2u8(handle->mac_addr, temp);
+ }
+ }
+
+ ((struct sdio_mmc_card *) card)->handle = handle;
+#ifdef STA_SUPPORT
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_INIT_SEMAPHORE(&handle->async_sem);
+#endif
+
+ /* Init SW */
+ if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto err_kmalloc;
+ }
+
+ do {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ handle->nl_sk = netlink_kernel_create(netlink_num, NULL);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ handle->nl_sk =
+ netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL,
+ THIS_MODULE);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ handle->nl_sk =
+ netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL, NULL,
+ THIS_MODULE);
+#else
+ handle->nl_sk =
+ netlink_kernel_create(&init_net, netlink_num, NL_MULTICAST_GROUP,
+ NULL, NULL, THIS_MODULE);
+#endif
+#endif
+#endif
+ if (handle->nl_sk) {
+ PRINTM(MINFO, "Netlink number = %d\n", netlink_num);
+ handle->netlink_num = netlink_num;
+ break;
+ }
+ netlink_num--;
+ } while (netlink_num > 0);
+
+ if (handle->nl_sk == NULL) {
+ PRINTM(MERROR,
+ "Could not initialize netlink event passing mechanism!\n");
+ goto err_kmalloc;
+ }
+
+ /* Create workqueue for main process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ /* For kernel less than 2.6.14 name can not be greater than 10 characters */
+ handle->workqueue = create_workqueue("MOAL_WORKQ");
+#else
+ handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
+#endif
+ if (!handle->workqueue)
+ goto err_kmalloc;
+
+ MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Starting re-association thread...\n");
+ handle->reassoc_thread.handle = handle;
+ woal_create_thread(woal_reassociation_thread,
+ &handle->reassoc_thread, "woal_reassoc_service");
+
+ while (!handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+
+ /* Register the device. Fill up the private data structure with relevant
+ information from the card and request for the required IRQ. */
+ if (woal_register_dev(handle) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "Failed to register wlan device!\n");
+ goto err_registerdev;
+ }
+
+ /* Init FW and HW */
+ if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto err_init_fw;
+ }
+
+ LEAVE();
+ return handle;
+
+ err_init_fw:
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_unregister_dev(handle);
+ err_registerdev:
+ handle->surprise_removed = MTRUE;
+#ifdef REASSOCIATION
+ if (handle->reassoc_thread.pid) {
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+ }
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+ woal_terminate_workqueue(handle);
+ err_kmalloc:
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ PRINTM(MINFO, "shutdown mlan\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ }
+ woal_free_moal_handle(handle);
+ if (index < MAX_MLAN_ADAPTER) {
+ m_handle[index] = NULL;
+ }
+ ((struct sdio_mmc_card *) card)->handle = NULL;
+ err_handle:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes the card.
+ *
+ * @param card A pointer to card
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+woal_remove_card(void *card)
+{
+ moal_handle *handle = NULL;
+ moal_private *priv = NULL;
+ mlan_status status;
+ int i;
+ int index = 0;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+ /* Find the correct handle */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] && (m_handle[index]->card == card)) {
+ handle = m_handle[index];
+ break;
+ }
+ }
+ if (!handle)
+ goto exit_remove;
+ handle->surprise_removed = MTRUE;
+
+ /* Stop data */
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if ((priv = handle->priv[i])) {
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+ }
+
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ /* Shutdown firmware */
+ PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
+ }
+ if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+
+ woal_terminate_workqueue(handle);
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Free reassoc_timer\n");
+ if (handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ if (handle->reassoc_thread.pid)
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_unregister_dev(handle);
+ /* Free adapter structure */
+ PRINTM(MINFO, "Free Adapter\n");
+ woal_free_moal_handle(handle);
+
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == handle) {
+ m_handle[index] = NULL;
+ break;
+ }
+ }
+ exit_remove:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function switch the drv_mode
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param mode new drv_mode to switch.
+ *
+ * @return MLAN_STATUS_SUCCESS /MLAN_STATUS_FAILURE /MLAN_STATUS_PENDING
+ */
+mlan_status
+woal_switch_drv_mode(moal_handle * handle, t_u32 mode)
+{
+ unsigned int i;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ if (woal_update_drv_tbl(handle, mode) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not update driver mode table!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Reset all interfaces */
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ woal_reset_intf(priv, MOAL_PROC_WAIT, MTRUE);
+
+ status = woal_shutdown_fw(priv, MOAL_CMD_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "func shutdown failed!\n");
+ goto exit;
+ }
+
+ /* Shutdown firmware */
+ PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
+ if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+
+ /* Unregister mlan */
+ if (handle->pmlan_adapter) {
+ mlan_unregister(handle->pmlan_adapter);
+ if (handle->malloc_count || handle->lock_count) {
+ PRINTM(MERROR,
+ "mlan has memory leak: malloc_count=%u lock_count=%u\n",
+ handle->malloc_count, handle->lock_count);
+ }
+ handle->pmlan_adapter = NULL;
+ }
+
+ handle->priv_num = 0;
+ drv_mode = mode;
+ /* Init SW */
+ if (woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto exit;
+ }
+ /* Init FW and HW */
+ if (woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto exit;
+ }
+ LEAVE();
+ return status;
+ exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function initializes module.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+woal_init_module(void)
+{
+ int ret = (int) MLAN_STATUS_SUCCESS;
+ int index = 0;
+
+ ENTER();
+
+ /* Init the wlan_private pointer array first */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ m_handle[index] = NULL;
+ }
+ /* Init mutex */
+ MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
+
+ wifi_add_dev();
+
+ /* Register with bus */
+ ret = woal_bus_register();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function cleans module
+ *
+ * @return N/A
+ */
+static void
+woal_cleanup_module(void)
+{
+ moal_handle *handle = NULL;
+ int index = 0;
+ int i;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ handle = m_handle[index];
+ if (!handle)
+ continue;
+ if (!handle->priv_num)
+ goto exit;
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ if (handle->is_suspended == MTRUE) {
+ woal_sdio_resume(&(((struct sdio_mmc_card *) handle->card)->func)->
+ dev);
+ }
+#endif
+#endif /* SDIO_SUSPEND_RESUME */
+
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE)
+ woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL);
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ handle->priv[i]->scan_request) {
+ cfg80211_scan_done(handle->priv[i]->scan_request, MTRUE);
+ handle->priv[i]->scan_request = NULL;
+ }
+#endif
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL);
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (handle->priv[i]->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ woal_cfg80211_mgmt_frame_ie(handle->priv[i], NULL, 0, NULL, 0,
+ NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ);
+#endif
+ }
+
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ woal_set_deep_sleep(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_CMD_WAIT, MFALSE, 0);
+
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ woal_shutdown_fw(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_CMD_WAIT);
+ }
+
+ exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ /* Unregister from bus */
+ woal_bus_unregister();
+ wifi_del_dev();
+
+ LEAVE();
+}
+
+module_init(woal_init_module);
+module_exit(woal_cleanup_module);
+
+module_param(fw_name, charp, 0);
+MODULE_PARM_DESC(fw_name, "Firmware name");
+module_param(req_fw_nowait, int, 0);
+MODULE_PARM_DESC(req_fw_nowait,
+ "0: Use request_firmware API; 1: Use request_firmware_nowait API");
+module_param(mac_addr, charp, 0);
+MODULE_PARM_DESC(mac_addr, "MAC address");
+#ifdef MFG_CMD_SUPPORT
+module_param(mfg_mode, int, 0);
+MODULE_PARM_DESC(mfg_mode,
+ "0: Download normal firmware; 1: Download MFG firmware");
+#endif /* MFG_CMD_SUPPORT */
+module_param(drv_mode, int, 0);
+#if defined(WIFI_DIRECT_SUPPORT)
+MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP; Bit 2: WIFIDIRECT");
+#else
+MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP");
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+#ifdef STA_SUPPORT
+module_param(max_sta_bss, int, 0);
+MODULE_PARM_DESC(max_sta_bss, "Number of STA interfaces (1)");
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+module_param(max_uap_bss, int, 0);
+MODULE_PARM_DESC(max_uap_bss, "Number of uAP interfaces (1)");
+#endif /* UAP_SUPPORT */
+#if defined(WIFI_DIRECT_SUPPORT)
+module_param(max_wfd_bss, int, 0);
+MODULE_PARM_DESC(max_wfd_bss, "Number of WIFIDIRECT interfaces (1)");
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+#ifdef DEBUG_LEVEL1
+module_param(drvdbg, uint, 0);
+MODULE_PARM_DESC(drvdbg, "Driver debug");
+#endif /* DEBUG_LEVEL1 */
+module_param(auto_ds, int, 0);
+MODULE_PARM_DESC(auto_ds,
+ "0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep");
+module_param(ps_mode, int, 0);
+MODULE_PARM_DESC(ps_mode,
+ "0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode");
+module_param(max_tx_buf, int, 0);
+MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)");
+#ifdef SDIO_SUSPEND_RESUME
+module_param(pm_keep_power, int, 1);
+MODULE_PARM_DESC(pm_keep_power, "1: PM keep power; 0: PM no power");
+#endif
+#if defined(STA_SUPPORT)
+module_param(cfg_11d, int, 0);
+MODULE_PARM_DESC(cfg_11d,
+ "0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d");
+#endif
+module_param(init_cfg, charp, 0);
+MODULE_PARM_DESC(init_cfg, "Init config file name");
+module_param(cal_data_cfg, charp, 0);
+MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name");
+module_param(minicard_pwrup, int, 1);
+MODULE_PARM_DESC(minicard_pwrup,
+ "1: Driver load clears PDn/Rst, unload sets (default); 0: Don't do this.");
+module_param(cfg80211_wext, int, 0);
+MODULE_PARM_DESC(cfg80211_wext,
+#ifdef STA_WEXT
+ "Bit 0: STA WEXT; "
+#endif
+#ifdef UAP_WEXT
+ "Bit 1: UAP WEXT; "
+#endif
+#ifdef STA_CFG80211
+ "Bit 2: STA CFG80211; "
+#endif
+#ifdef UAP_CFG80211
+ "Bit 3: UAP CFG80211;"
+#endif
+ );
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.h b/drivers/net/wireless/sd8797/mlinux/moal_main.h
new file mode 100644
index 000000000000..32426a149779
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_main.h
@@ -0,0 +1,1564 @@
+/** @file moal_main.h
+ *
+ * @brief This file contains wlan driver specific defines etc.
+ *
+ * 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
+********************************************************/
+
+#ifndef _MOAL_MAIN_H
+#define _MOAL_MAIN_H
+
+/* warnfix for FS redefination if any? */
+#ifdef FS
+#undef FS
+#endif
+
+/* Linux header files */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/list.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#endif
+
+/* ASM files */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Net header files */
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/firmware.h>
+
+#include "mlan.h"
+#include "moal_shim.h"
+/* Wireless header */
+#include <linux/wireless.h>
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include <net/lib80211.h>
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#include <net/iw_handler.h>
+#include "moal_wext.h"
+#endif
+#ifdef STA_WEXT
+#include "moal_priv.h"
+#endif
+
+/** Define BOOLEAN */
+typedef t_u8 BOOLEAN;
+
+/** Driver version */
+extern char driver_version[];
+
+/** Private structure for MOAL */
+typedef struct _moal_private moal_private;
+/** Handle data structure for MOAL */
+typedef struct _moal_handle moal_handle;
+
+/** Hardware status codes */
+typedef enum _MOAL_HARDWARE_STATUS
+{
+ HardwareStatusReady,
+ HardwareStatusInitializing,
+ HardwareStatusFwReady,
+ HardwareStatusReset,
+ HardwareStatusClosing,
+ HardwareStatusNotReady
+} MOAL_HARDWARE_STATUS;
+
+/** moal_wait_option */
+enum
+{
+ MOAL_NO_WAIT,
+ MOAL_IOCTL_WAIT,
+ MOAL_CMD_WAIT,
+ MOAL_PROC_WAIT,
+ MOAL_WSTATS_WAIT
+};
+
+/** moal_main_state */
+enum
+{
+ MOAL_STATE_IDLE,
+ MOAL_RECV_INT,
+ MOAL_ENTER_WORK_QUEUE,
+ MOAL_START_MAIN_PROCESS,
+ MOAL_END_MAIN_PROCESS
+};
+
+/** HostCmd_Header */
+typedef struct _HostCmd_Header
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+} HostCmd_Header;
+
+#ifndef MIN
+/** Find minimum */
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * OS timer specific
+ */
+
+/** Timer structure */
+typedef struct _moal_drv_timer
+{
+ /** Timer list */
+ struct timer_list tl;
+ /** Timer function */
+ void (*timer_function) (void *context);
+ /** Timer function context */
+ void *function_context;
+ /** Time period */
+ t_u32 time_period;
+ /** Is timer periodic ? */
+ t_u32 timer_is_periodic;
+ /** Is timer cancelled ? */
+ t_u32 timer_is_canceled;
+} moal_drv_timer, *pmoal_drv_timer;
+
+/**
+ * @brief Timer handler
+ *
+ * @param fcontext Timer context
+ *
+ * @return N/A
+ */
+static inline void
+woal_timer_handler(unsigned long fcontext)
+{
+ pmoal_drv_timer timer = (pmoal_drv_timer) fcontext;
+
+ timer->timer_function(timer->function_context);
+
+ if (timer->timer_is_periodic == MTRUE) {
+ mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000));
+ } else {
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ }
+}
+
+/**
+ * @brief Initialize timer
+ *
+ * @param timer Timer structure
+ * @param TimerFunction Timer function
+ * @param FunctionContext Timer function context
+ *
+ * @return N/A
+ */
+static inline void
+woal_initialize_timer(pmoal_drv_timer timer,
+ void (*TimerFunction) (void *context),
+ void *FunctionContext)
+{
+ /* First, setup the timer to trigger the wlan_timer_handler proxy */
+ init_timer(&timer->tl);
+ timer->tl.function = woal_timer_handler;
+ timer->tl.data = (t_ptr) timer;
+
+ /* Then tell the proxy which function to call and what to pass it */
+ timer->timer_function = TimerFunction;
+ timer->function_context = FunctionContext;
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ timer->timer_is_periodic = MFALSE;
+}
+
+/**
+ * @brief Modify timer
+ *
+ * @param timer Timer structure
+ * @param MillisecondPeriod Time period in millisecond
+ *
+ * @return N/A
+ */
+static inline void
+woal_mod_timer(pmoal_drv_timer timer, t_u32 MillisecondPeriod)
+{
+ timer->time_period = MillisecondPeriod;
+ mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000);
+ timer->timer_is_canceled = MFALSE;
+}
+
+/**
+ * @brief Cancel timer
+ *
+ * @param timer Timer structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_cancel_timer(moal_drv_timer * timer)
+{
+ del_timer(&timer->tl);
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+}
+
+#ifdef REASSOCIATION
+/*
+ * OS Thread Specific
+ */
+
+#include <linux/kthread.h>
+
+/** Kernel thread structure */
+typedef struct _moal_thread
+{
+ /** Task control structrue */
+ struct task_struct *task;
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t wait_q;
+ /** PID */
+ pid_t pid;
+ /** Pointer to moal_handle */
+ void *handle;
+} moal_thread;
+
+/**
+ * @brief Activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void
+woal_activate_thread(moal_thread * thr)
+{
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->wait_q);
+
+ /** Record the thread pid */
+ thr->pid = current->pid;
+}
+
+/**
+ * @brief De-activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void
+woal_deactivate_thread(moal_thread * thr)
+{
+ /* Reset the pid */
+ thr->pid = 0;
+}
+
+/**
+ * @brief Create and run the thread
+ *
+ * @param threadfunc Thread function
+ * @param thr Thread structure
+ * @param name Thread name
+ * @return N/A
+ */
+static inline void
+woal_create_thread(int (*threadfunc) (void *), moal_thread * thr, char *name)
+{
+ /* Create and run the thread */
+ thr->task = kthread_run(threadfunc, thr, "%s", name);
+}
+#endif /* REASSOCIATION */
+
+/* The following macros are neccessary to retain compatibility
+ * around the workqueue chenges happened in kernels >= 2.6.20:
+ * - INIT_WORK changed to take 2 arguments and let the work function
+ * get its own data through the container_of macro
+ * - delayed works have been split from normal works to save some
+ * memory usage in struct work_struct
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK INIT_WORK
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK INIT_DELAYED_WORK
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m.work)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+
+/**
+ * @brief Schedule timeout
+ *
+ * @param millisec Timeout duration in milli second
+ *
+ * @return N/A
+ */
+static inline void
+woal_sched_timeout(t_u32 millisec)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout((millisec * HZ) / 1000);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#define IN6PTON_XDIGIT 0x00010000
+#define IN6PTON_DIGIT 0x00020000
+#define IN6PTON_COLON_MASK 0x00700000
+#define IN6PTON_COLON_1 0x00100000 /* single : requested */
+#define IN6PTON_COLON_2 0x00200000 /* second : requested */
+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
+#define IN6PTON_DOT 0x00800000 /* . */
+#define IN6PTON_DELIM 0x10000000
+#define IN6PTON_NULL 0x20000000 /* first/tail */
+#define IN6PTON_UNKNOWN 0x40000000
+
+static inline int
+xdigit2bin(char c, int delim)
+{
+ if (c == delim || c == '\0')
+ return IN6PTON_DELIM;
+ if (c == ':')
+ return IN6PTON_COLON_MASK;
+ if (c == '.')
+ return IN6PTON_DOT;
+ if (c >= '0' && c <= '9')
+ return (IN6PTON_XDIGIT | IN6PTON_DIGIT | (c - '0'));
+ if (c >= 'a' && c <= 'f')
+ return (IN6PTON_XDIGIT | (c - 'a' + 10));
+ if (c >= 'A' && c <= 'F')
+ return (IN6PTON_XDIGIT | (c - 'A' + 10));
+ if (delim == -1)
+ return IN6PTON_DELIM;
+ return IN6PTON_UNKNOWN;
+}
+
+static inline int
+in4_pton(const char *src, int srclen, u8 * dst, int delim, const char **end)
+{
+ const char *s;
+ u8 *d;
+ u8 dbuf[4];
+ int ret = 0;
+ int i;
+ int w = 0;
+
+ if (srclen < 0)
+ srclen = strlen(src);
+ s = src;
+ d = dbuf;
+ i = 0;
+ while (1) {
+ int c;
+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
+ if (!
+ (c &
+ (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
+ IN6PTON_COLON_MASK))) {
+ goto out;
+ }
+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (w == 0)
+ goto out;
+ *d++ = w & 0xff;
+ w = 0;
+ i++;
+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (i != 4)
+ goto out;
+ break;
+ }
+ goto cont;
+ }
+ w = (w * 10) + c;
+ if ((w & 0xffff) > 255) {
+ goto out;
+ }
+ cont:
+ if (i >= 4)
+ goto out;
+ s++;
+ srclen--;
+ }
+ ret = 1;
+ memcpy(dst, dbuf, sizeof(dbuf));
+ out:
+ if (end)
+ *end = s;
+ return ret;
+}
+#endif /* < 2.6.19 */
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+
+/** Get module */
+#define MODULE_GET try_module_get(THIS_MODULE)
+/** Put module */
+#define MODULE_PUT module_put(THIS_MODULE)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) init_MUTEX(x)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) init_MUTEX_LOCKED(x)
+#else
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) sema_init(x,1)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) sema_init(x,0)
+#endif
+
+/** Acquire semaphore and with blocking */
+#define MOAL_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
+/** Acquire semaphore without blocking */
+#define MOAL_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
+/** Release semaphore */
+#define MOAL_REL_SEMAPHORE(x) up(x)
+
+/** Request FW timeout in second */
+#define REQUEST_FW_TIMEOUT 30
+
+/** Default watchdog timeout */
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
+
+#ifdef UAP_SUPPORT
+/** Default watchdog timeout
+ Increase the value to avoid kernel Tx timeout message in case
+ station in PS mode or left.
+ The default value of PS station ageout timer is 40 seconds.
+ Hence, the watchdog timer is set to a value higher than it.
+*/
+#define MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT (41 * HZ)
+#endif
+
+/** Threshold value of number of times the Tx timeout happened */
+#define NUM_TX_TIMEOUT_THRESHOLD 5
+
+/** 10 seconds */
+#define MOAL_TIMER_10S 10000
+/** 5 seconds */
+#define MOAL_TIMER_5S 5000
+/** 1 second */
+#define MOAL_TIMER_1S 1000
+
+/** Default value of re-assoc timer */
+#define REASSOC_TIMER_DEFAULT 500
+
+/** Netlink protocol number */
+#define NETLINK_MARVELL (MAX_LINKS - 1)
+/** Netlink maximum payload size */
+#define NL_MAX_PAYLOAD 1024
+/** Netlink multicast group number */
+#define NL_MULTICAST_GROUP 1
+
+/** MAX Tx Pending count */
+#define MAX_TX_PENDING 100
+
+/** LOW Tx Pending count */
+#define LOW_TX_PENDING 80
+
+/** Offset for subcommand */
+#define SUBCMD_OFFSET 4
+
+/** Macro to extract the TOS field from a skb */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#define SKB_TOS(skb) (ip_hdr(skb)->tos)
+#else
+#define SKB_TOS(skb) (skb->nh.iph->tos)
+#endif
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** Offset for DSCP in the tos field */
+#define DSCP_OFFSET 2
+
+/** wait_queue structure */
+typedef struct _wait_queue
+{
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t *wait;
+ /** Wait condition */
+ BOOLEAN condition;
+ /** Start time */
+ t_u32 start_time;
+ /** Status from MLAN */
+ mlan_status status;
+} wait_queue, *pwait_queue;
+
+/** Auto Rate */
+#define AUTO_RATE 0xFF
+
+#define STA_WEXT_MASK MBIT(0)
+#define UAP_WEXT_MASK MBIT(1)
+#define STA_CFG80211_MASK MBIT(2)
+#define UAP_CFG80211_MASK MBIT(3)
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+/** Is STA CFG80211 enabled in module param */
+#define IS_STA_CFG80211(x) (x & STA_CFG80211_MASK)
+#endif
+#endif
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+/** Is UAP CFG80211 enabled in module param */
+#define IS_UAP_CFG80211(x) (x & UAP_CFG80211_MASK)
+#endif
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/** Is UAP or STA CFG80211 enabled in module param */
+#define IS_STA_OR_UAP_CFG80211(x) (x & (STA_CFG80211_MASK | UAP_CFG80211_MASK))
+#endif
+
+#ifdef STA_WEXT
+/** Is STA WEXT enabled in module param */
+#define IS_STA_WEXT(x) (x & STA_WEXT_MASK)
+#endif /* STA_WEXT */
+#ifdef UAP_WEXT
+/** Is UAP WEXT enabled in module param */
+#define IS_UAP_WEXT(x) (x & UAP_WEXT_MASK)
+#endif /* UAP_WEXT */
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/** Is UAP or STA WEXT enabled in module param */
+#define IS_STA_OR_UAP_WEXT(x) (x & (STA_WEXT_MASK | UAP_WEXT_MASK))
+#endif
+
+#ifdef STA_SUPPORT
+/** Driver mode STA bit */
+#define DRV_MODE_STA MBIT(0)
+/** Maximum STA BSS */
+#define MAX_STA_BSS 1
+/** Default STA BSS */
+#define DEF_STA_BSS 1
+#endif
+#ifdef UAP_SUPPORT
+/** Driver mode uAP bit */
+#define DRV_MODE_UAP MBIT(1)
+/** Maximum uAP BSS */
+#define MAX_UAP_BSS 2
+/** Default uAP BSS */
+#define DEF_UAP_BSS 1
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Driver mode WIFIDIRECT bit */
+#define DRV_MODE_WIFIDIRECT MBIT(2)
+/** Maximum WIFIDIRECT BSS */
+#define MAX_WIFIDIRECT_BSS 1
+/** Default WIFIDIRECT BSS */
+#define DEF_WIFIDIRECT_BSS 1
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+typedef struct _moal_drv_mode
+{
+ /** driver mode */
+ t_u16 drv_mode;
+ /** total number of interfaces */
+ t_u16 intf_num;
+ /** attribute of bss */
+ mlan_bss_attr *bss_attr;
+ /** name of firmware image */
+ char *fw_name;
+} moal_drv_mode;
+
+#ifdef PROC_DEBUG
+/** Debug data */
+struct debug_data
+{
+ /** Name */
+ char name[32];
+ /** Size */
+ t_u32 size;
+ /** Address */
+ t_ptr addr;
+};
+
+/** Private debug data */
+struct debug_data_priv
+{
+ /** moal_private handle */
+ moal_private *priv;
+ /** Debug items */
+ struct debug_data *items;
+ /** numbre of item */
+ int num_of_items;
+};
+#endif
+
+/** Maximum IP address buffer length */
+#define IPADDR_MAX_BUF 20
+/** IP address operation: Remove */
+#define IPADDR_OP_REMOVE 0
+
+struct tcp_sess
+{
+ struct list_head link;
+ /** tcp session info */
+ t_u32 src_ip_addr;
+ t_u32 dst_ip_addr;
+ t_u16 src_tcp_port;
+ t_u16 dst_tcp_port;
+ /** tcp window info */
+ t_u8 rx_win_opt;
+ t_u32 rx_win_scale;
+ /** warming up counter */
+ t_u32 start_cnt;
+ /** tx ack packet info */
+ t_u32 ack_seq;
+ t_u32 ack_cnt;
+};
+
+/** Private structure for MOAL */
+struct _moal_private
+{
+ /** Handle structure */
+ moal_handle *phandle;
+ /** Tx timeout count */
+ t_u32 num_tx_timeout;
+ /** BSS index */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS role */
+ t_u8 bss_role;
+ /** MAC address information */
+ t_u8 current_addr[ETH_ALEN];
+ /** Media connection status */
+ BOOLEAN media_connected;
+#ifdef UAP_SUPPORT
+ /** uAP started or not */
+ BOOLEAN bss_started;
+#endif
+#ifdef STA_SUPPORT
+ /** scan type */
+ t_u8 scan_type;
+ /** bg_scan_start */
+ t_u8 bg_scan_start;
+ /** bg_scan reported */
+ t_u8 bg_scan_reported;
+ /** bg_scan config */
+ wlan_bgscan_cfg scan_cfg;
+#endif
+ /** Net device pointer */
+ struct net_device *netdev;
+ /** Net device statistics structure */
+ struct net_device_stats stats;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /** Country code for regulatory domain */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Wireless device pointer */
+ struct wireless_dev *wdev;
+ /** channel parameter for UAP/GO */
+ t_u16 channel;
+ /** cipher */
+ t_u32 cipher;
+ /** key index */
+ t_u8 key_index;
+ /** key len */
+ t_u16 key_len;
+ /** key data */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** probereq index for mgmt ie */
+ t_u16 probereq_index;
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ /** CFG80211 scan request description */
+ struct cfg80211_scan_request *scan_request;
+ /** CFG80211 association description */
+ t_u8 cfg_bssid[ETH_ALEN];
+ /** Disconnect request from CFG80211 */
+ bool cfg_disconnect;
+ /** rssi_threshold */
+ s32 cqm_rssi_thold;
+ /** rssi hysteresis */
+ u32 cqm_rssi_hyst;
+ /** last rssi_low */
+ u8 last_rssi_low;
+ /** last rssi_high */
+ u8 last_rssi_high;
+ /** mrvl rssi threshold */
+ u8 mrvl_rssi_low;
+ /** rssi status */
+ u32 rssi_status;
+#endif /* STA_SUPPORT */
+#endif /* STA_CFG80211 */
+ /** IOCTL wait queue */
+ wait_queue_head_t ioctl_wait_q __ATTRIB_ALIGN__;
+ /** CMD wait queue */
+ wait_queue_head_t cmd_wait_q __ATTRIB_ALIGN__;
+#ifdef CONFIG_PROC_FS
+ /** Proc entry */
+ struct proc_dir_entry *proc_entry;
+ /** Proc entry name */
+ t_s8 proc_entry_name[IFNAMSIZ];
+ /** PROC wait queue */
+ wait_queue_head_t proc_wait_q __ATTRIB_ALIGN__;
+#endif /* CONFIG_PROC_FS */
+#ifdef STA_SUPPORT
+ /** Nickname */
+ t_u8 nick_name[16];
+ /** AdHoc link sensed flag */
+ BOOLEAN is_adhoc_link_sensed;
+ /** Current WEP key index */
+ t_u16 current_key_index;
+#ifdef REASSOCIATION
+ mlan_ssid_bssid prev_ssid_bssid;
+ /** Re-association required */
+ BOOLEAN reassoc_required;
+ /** Flag of re-association on/off */
+ BOOLEAN reassoc_on;
+#endif /* REASSOCIATION */
+ /** Report scan result */
+ t_u8 report_scan_result;
+ /** wpa_version */
+ t_u8 wpa_version;
+ /** key mgmt */
+ t_u8 key_mgmt;
+ /** rx_filter */
+ t_u8 rx_filter;
+#endif /* STA_SUPPORT */
+ /** Rate index */
+ t_u16 rate_index;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ /** IW statistics */
+ struct iw_statistics w_stats;
+ /** w_stats wait queue */
+ wait_queue_head_t w_stats_wait_q __ATTRIB_ALIGN__;
+#endif
+#ifdef UAP_WEXT
+ /** Pairwise Cipher used for WPA/WPA2 mode */
+ t_u16 pairwise_cipher;
+ /** Group Cipher */
+ t_u16 group_cipher;
+ /** Protocol stored during uap wext configuratoin */
+ t_u16 uap_protocol;
+ /** Key Mgmt whether PSK or 1x */
+ t_u16 uap_key_mgmt;
+ /** Beacon IE length from hostapd */
+ t_u16 bcn_ie_len;
+ /** Beacon IE buffer from hostapd */
+ t_u8 bcn_ie_buf[MAX_IE_SIZE];
+#endif
+
+#ifdef PROC_DEBUG
+ /** MLAN debug info */
+ struct debug_data_priv items_priv;
+#endif
+
+ /** tcp session queue */
+ struct list_head tcp_sess_queue;
+ /** TCP Ack enhance flag */
+ t_u8 enable_tcp_ack_enh;
+};
+
+/** Handle data structure for MOAL */
+struct _moal_handle
+{
+ /** MLAN adapter structure */
+ t_void *pmlan_adapter;
+ /** Private pointer */
+ moal_private *priv[MLAN_MAX_BSS_NUM];
+ /** Priv number */
+ t_u8 priv_num;
+ /** Bss attr */
+ moal_drv_mode drv_mode;
+ /** set mac address flag */
+ t_u8 set_mac_addr;
+ /** MAC address */
+ t_u8 mac_addr[ETH_ALEN];
+#ifdef CONFIG_PROC_FS
+ /** Proc top level directory entry */
+ struct proc_dir_entry *proc_mwlan;
+#endif
+ /** Firmware */
+ const struct firmware *firmware;
+ /** Firmware request start time */
+ struct timeval req_fw_time;
+ /** Init config file */
+ const struct firmware *user_data;
+ /** Hotplug device */
+ struct device *hotplug_device;
+ /** STATUS variables */
+ MOAL_HARDWARE_STATUS hardware_status;
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ BOOLEAN surprise_removed;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** Init wait queue token */
+ t_u16 init_wait_q_woken;
+ /** Init wait queue */
+ wait_queue_head_t init_wait_q __ATTRIB_ALIGN__;
+#if defined(SDIO_SUSPEND_RESUME)
+ /** Device suspend flag */
+ BOOLEAN is_suspended;
+#ifdef SDIO_SUSPEND_RESUME
+ /** suspend notify flag */
+ BOOLEAN suspend_notify_req;
+#endif
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** Host Sleep activated event wait queue token */
+ t_u16 hs_activate_wait_q_woken;
+ /** Host Sleep activated event wait queue */
+ wait_queue_head_t hs_activate_wait_q __ATTRIB_ALIGN__;
+#endif
+ /** Card pointer */
+ t_void *card;
+ /** Rx pending in MLAN */
+ atomic_t rx_pending;
+ /** Tx packet pending count in mlan */
+ atomic_t tx_pending;
+ /** IOCTL pending count in mlan */
+ atomic_t ioctl_pending;
+ /** Malloc count */
+ t_u32 malloc_count;
+ /** lock count */
+ t_u32 lock_count;
+ /** mlan buffer alloc count */
+ t_u32 mbufalloc_count;
+#if defined(SDIO_SUSPEND_RESUME)
+ /** hs skip count */
+ t_u32 hs_skip_count;
+ /** hs force count */
+ t_u32 hs_force_count;
+ /** suspend_fail flag */
+ BOOLEAN suspend_fail;
+#endif
+#ifdef REASSOCIATION
+ /** Re-association thread */
+ moal_thread reassoc_thread;
+ /** Re-association timer set flag */
+ BOOLEAN is_reassoc_timer_set;
+ /** Re-association timer */
+ moal_drv_timer reassoc_timer __ATTRIB_ALIGN__;
+ /** */
+ struct semaphore reassoc_sem;
+ /** Bitmap for re-association on/off */
+ t_u8 reassoc_on;
+#endif /* REASSOCIATION */
+ /** Driver workqueue */
+ struct workqueue_struct *workqueue;
+ /** main work */
+ struct work_struct main_work;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#ifdef WIFI_DIRECT_SUPPORT
+ /** remain on channel flag */
+ t_u8 remain_on_channel;
+ /** ieee802_11_channel */
+ struct ieee80211_channel chan;
+ /** channel type */
+ enum nl80211_channel_type channel_type;
+ /** cookie */
+ t_u64 cookie;
+#endif
+#endif
+ /** Read SDIO registers for debugging */
+ t_u32 sdio_reg_dbg;
+ /** Netlink kernel socket */
+ struct sock *nl_sk;
+ /** Netlink kernel socket number */
+ t_u32 netlink_num;
+ /** w_stats wait queue token */
+ BOOLEAN meas_wait_q_woken;
+ /** w_stats wait queue */
+ wait_queue_head_t meas_wait_q __ATTRIB_ALIGN__;
+ /** Measurement start jiffes */
+ t_u32 meas_start_jiffies;
+ /** CAC checking period flag */
+ BOOLEAN cac_period;
+ /** BSS START command delay executing flag */
+ BOOLEAN delay_bss_start;
+ /** SSID,BSSID parameter of delay executing */
+ mlan_ssid_bssid delay_ssid_bssid;
+#ifdef DFS_TESTING_SUPPORT
+ /** cac period length, valid only when dfs testing is enabled */
+ t_u32 cac_period_jiffies;
+#endif
+ /** handle index - for multiple card supports */
+ t_u8 handle_idx;
+#ifdef SDIO_MMC_DEBUG
+ /** cmd53 write state */
+ u8 cmd53w;
+ /** cmd53 read state */
+ u8 cmd53r;
+#endif
+#ifdef STA_SUPPORT
+ /** Scan pending on blocked flag */
+ t_u8 scan_pending_on_block;
+ /** Async scan semaphore */
+ struct semaphore async_sem;
+
+#endif
+ /** main state */
+ t_u8 main_state;
+ /** cmd52 function */
+ t_u8 cmd52_func;
+ /** cmd52 register */
+ t_u8 cmd52_reg;
+ /** cmd52 value */
+ t_u8 cmd52_val;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ /** spinlock to stop_queue/wake_queue*/
+ spinlock_t queue_lock;
+#endif
+};
+
+/**
+ * @brief set trans_start for each TX queue.
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_set_trans_start(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ netdev_get_tx_queue(dev, i)->trans_start = jiffies;
+ }
+#endif
+ dev->trans_start = jiffies;
+}
+
+/**
+ * @brief Start queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_start_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ netif_start_queue(dev);
+#else
+ netif_tx_start_all_queues(dev);
+#endif
+}
+
+/**
+ * @brief Stop queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_stop_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ unsigned long flags;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ spin_lock_irqsave(&priv->phandle->queue_lock, flags);
+ woal_set_trans_start(dev);
+ if (!netif_queue_stopped(dev))
+ netif_tx_stop_all_queues(dev);
+ spin_unlock_irqrestore(&priv->phandle->queue_lock, flags);
+#else
+ woal_set_trans_start(dev);
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+#endif
+}
+
+/**
+ * @brief wake queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_wake_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ unsigned long flags;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ spin_lock_irqsave(&priv->phandle->queue_lock, flags);
+ if (netif_queue_stopped(dev))
+ netif_tx_wake_all_queues(dev);
+ spin_unlock_irqrestore(&priv->phandle->queue_lock, flags);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+}
+
+/** Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX 256 /* In bytes */
+
+/** Debug Macro definition*/
+#ifdef DEBUG_LEVEL1
+extern t_u32 drvdbg;
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(msg...) do {if (drvdbg & MINFO) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MWARN(msg...) do {if (drvdbg & MWARN) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MENTRY(msg...) do {if (drvdbg & MENTRY) printk(KERN_DEBUG msg);} while(0)
+#else
+#define PRINTM_MINFO(msg...) do {} while (0)
+#define PRINTM_MWARN(msg...) do {} while (0)
+#define PRINTM_MENTRY(msg...) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(msg...) do {if (drvdbg & MFW_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MCMD_D(msg...) do {if (drvdbg & MCMD_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MDAT_D(msg...) do {if (drvdbg & MDAT_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MIF_D(msg...) do {if (drvdbg & MIF_D) printk(KERN_DEBUG msg);} while(0)
+
+#define PRINTM_MIOCTL(msg...) do {if (drvdbg & MIOCTL) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MINTR(msg...) do {if (drvdbg & MINTR) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MEVENT(msg...) do {if (drvdbg & MEVENT) printk(msg);} while(0)
+#define PRINTM_MCMND(msg...) do {if (drvdbg & MCMND) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MDATA(msg...) do {if (drvdbg & MDATA) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MERROR(msg...) do {if (drvdbg & MERROR) printk(KERN_ERR msg);} while(0)
+#define PRINTM_MFATAL(msg...) do {if (drvdbg & MFATAL) printk(KERN_ERR msg);} while(0)
+#define PRINTM_MMSG(msg...) do {if (drvdbg & MMSG) printk(KERN_ALERT msg);} while(0)
+
+#define PRINTM(level,msg...) PRINTM_##level(msg)
+
+#else
+
+#define PRINTM(level,msg...) do {} while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Wait until a condition becomes true */
+#define MASSERT(cond) \
+do { \
+ if (!(cond)) { \
+ PRINTM(MFATAL, "ASSERT: %s: %i\n", __FUNCTION__, __LINE__); \
+ panic("Assert failed: Panic!"); \
+ } \
+} while(0)
+
+/** Log entry point for debugging */
+#define ENTER() PRINTM(MENTRY, "Enter: %s\n", \
+ __FUNCTION__)
+/** Log exit point for debugging */
+#define LEAVE() PRINTM(MENTRY, "Leave: %s\n", \
+ __FUNCTION__)
+
+#ifdef DEBUG_LEVEL1
+#define DBG_DUMP_BUF_LEN 64
+#define MAX_DUMP_PER_LINE 16
+
+static inline void
+hexdump(char *prompt, t_u8 * buf, int len)
+{
+ int i;
+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+ char *ptr = dbgdumpbuf;
+
+ printk(KERN_DEBUG "%s:\n", prompt);
+ for (i = 1; i <= len; i++) {
+ ptr += snprintf(ptr, 4, "%02x ", *buf);
+ buf++;
+ if (i % MAX_DUMP_PER_LINE == 0) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ ptr = dbgdumpbuf;
+ }
+ }
+ if (len % MAX_DUMP_PER_LINE) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ }
+}
+
+#define DBG_HEXDUMP_MERROR(x,y,z) do {if (drvdbg & MERROR) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MCMD_D(x,y,z) do {if (drvdbg & MCMD_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MDAT_D(x,y,z) do {if (drvdbg & MDAT_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MIF_D(x,y,z) do {if (drvdbg & MIF_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MEVT_D(x,y,z) do {if (drvdbg & MEVT_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MFW_D(x,y,z) do {if (drvdbg & MFW_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
+
+#else
+/** Do nothing since debugging is not turned on */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
+#endif
+
+#ifdef DEBUG_LEVEL2
+#define HEXDUMP(x,y,z) do {if (drvdbg & MINFO) hexdump(x,y,z);} while(0)
+#else
+/** Do nothing since debugging is not turned on */
+#define HEXDUMP(x,y,z) do {} while (0)
+#endif
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert from 16 bit little endian format to CPU format */
+#define woal_le16_to_cpu(x) le16_to_cpu(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define woal_le32_to_cpu(x) le32_to_cpu(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define woal_le64_to_cpu(x) le64_to_cpu(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define woal_cpu_to_le16(x) cpu_to_le16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define woal_cpu_to_le32(x) cpu_to_le32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define woal_cpu_to_le64(x) cpu_to_le64(x)
+#else
+/** Do nothing */
+#define woal_le16_to_cpu(x) x
+/** Do nothing */
+#define woal_le32_to_cpu(x) x
+/** Do nothing */
+#define woal_le64_to_cpu(x) x
+/** Do nothing */
+#define woal_cpu_to_le16(x) x
+/** Do nothing */
+#define woal_cpu_to_le32(x) x
+/** Do nothing */
+#define woal_cpu_to_le64(x) x
+#endif
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS role
+ *
+ * @param handle A pointer to moal_handle
+ * @param bss_role BSS role or MLAN_BSS_ROLE_ANY
+ *
+ * @return Pointer to moal_private
+ */
+static inline moal_private *
+woal_get_priv(moal_handle * handle, mlan_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (bss_role == MLAN_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(handle->priv[i]) == bss_role)
+ return (handle->priv[i]);
+ }
+ }
+ return NULL;
+}
+
+/** Max line length allowed in init config file */
+#define MAX_LINE_LEN 256
+/** Max MAC address string length allowed */
+#define MAX_MAC_ADDR_LEN 18
+/** Max register type/offset/value etc. parameter length allowed */
+#define MAX_PARAM_LEN 12
+
+/** HostCmd_CMD_CFG_DATA for CAL data */
+#define HostCmd_CMD_CFG_DATA 0x008f
+/** HostCmd action set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** HostCmd CAL data header length */
+#define CFG_DATA_HEADER_LEN 6
+
+typedef struct _HostCmd_DS_GEN
+{
+ t_u16 command;
+ t_u16 size;
+ t_u16 seq_num;
+ t_u16 result;
+} HostCmd_DS_GEN;
+
+typedef struct _HostCmd_DS_802_11_CFG_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+ t_u8 data[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CFG_DATA;
+
+/** combo scan header */
+#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
+/** combo scan header size */
+#define WEXT_CSCAN_HEADER_SIZE 12
+/** combo scan ssid section */
+#define WEXT_CSCAN_SSID_SECTION 'S'
+/** commbo scan channel section */
+#define WEXT_CSCAN_CHANNEL_SECTION 'C'
+/** commbo scan passive dwell section */
+#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
+/** commbo scan home dwell section */
+#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
+/** BGSCAN RSSI section */
+#define WEXT_BGSCAN_RSSI_SECTION 'R'
+/** BGSCAN SCAN INTERVAL SECTION */
+#define WEXT_BGSCAN_INTERVAL_SECTION 'T'
+/** BGSCAN REPEAT SECTION */
+#define WEXT_BGSCAN_REPEAT_SECTION 'E'
+
+/** band AUTO */
+#define WIFI_FREQUENCY_BAND_AUTO 0
+/** band 5G */
+#define WIFI_FREQUENCY_BAND_5GHZ 1
+/** band 2G */
+#define WIFI_FREQUENCY_BAND_2GHZ 2
+/** All band */
+#define WIFI_FREQUENCY_ALL_BAND 3
+
+/** Rx filter: IPV4 multicast */
+#define RX_FILTER_IPV4_MULTICAST 1
+/** Rx filter: broadcast */
+#define RX_FILTER_BROADCAST 2
+/** Rx filter: unicast */
+#define RX_FILTER_UNICAST 4
+/** Rx filter: IPV6 multicast */
+#define RX_FILTER_IPV6_MULTICAST 8
+
+/** Convert ASCII string to hex value */
+int woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen);
+/** Convert mac address from string to t_u8 buffer */
+void woal_mac2u8(t_u8 * mac_addr, char *buf);
+/** Extract token from string */
+char *woal_strsep(char **s, char delim, char esc);
+/** Return int value of a given ASCII string */
+mlan_status woal_atoi(int *data, char *a);
+/** Return hex value of a given ASCII string */
+int woal_atox(char *a);
+/** Allocate buffer */
+pmlan_buffer woal_alloc_mlan_buffer(moal_handle * handle, int size);
+/** Allocate IOCTL request buffer */
+pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size);
+/** Free buffer */
+void woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf);
+/** Get private structure of a BSS by index */
+moal_private *woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index);
+/* Functions in interface module */
+/** Add card */
+moal_handle *woal_add_card(void *card);
+/** Remove card */
+mlan_status woal_remove_card(void *card);
+/** broadcast event */
+mlan_status woal_broadcast_event(moal_private * priv, t_u8 * payload,
+ t_u32 len);
+/** switch driver mode */
+mlan_status woal_switch_drv_mode(moal_handle * handle, t_u32 mode);
+
+/** Interrupt handler */
+void woal_interrupt(moal_handle * handle);
+
+#ifdef STA_WEXT
+#endif
+/** Get version */
+void woal_get_version(moal_handle * handle, char *version, int maxlen);
+/** Get Driver Version */
+int woal_get_driver_version(moal_private * priv, struct ifreq *req);
+/** Get extended driver version */
+int woal_get_driver_verext(moal_private * priv, struct ifreq *ireq);
+/** Mgmt frame forward registration */
+int woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action,
+ t_u32 * pmgmt_subtype_mask, t_u8 wait_option);
+#ifdef DEBUG_LEVEL1
+/** Set driver debug bit masks */
+int woal_set_drvdbg(moal_private * priv, t_u32 drvdbg);
+#endif
+/** Set/Get TX beamforming configurations */
+mlan_status woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action,
+ mlan_ds_11n_tx_bf_cfg * bf_cfg);
+/** Request MAC address setting */
+mlan_status woal_request_set_mac_address(moal_private * priv);
+/** Request multicast list setting */
+void woal_request_set_multicast_list(moal_private * priv,
+ struct net_device *dev);
+/** Request IOCTL action */
+mlan_status woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req,
+ t_u8 wait_option);
+mlan_status woal_request_soft_reset(moal_handle * handle);
+#ifdef PROC_DEBUG
+/** Get debug information */
+mlan_status woal_get_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info);
+/** Set debug information */
+mlan_status woal_set_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info);
+#endif
+/** Disconnect */
+mlan_status woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac);
+/** associate */
+mlan_status woal_bss_start(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Request firmware information */
+mlan_status woal_request_get_fw_info(moal_private * priv, t_u8 wait_option,
+ mlan_fw_info * fw_info);
+/** Set/get Host Sleep parameters */
+mlan_status woal_set_get_hs_params(moal_private * priv, t_u16 action,
+ t_u8 wait_option, mlan_ds_hs_cfg * hscfg);
+/** Cancel Host Sleep configuration */
+mlan_status woal_cancel_hs(moal_private * priv, t_u8 wait_option);
+#if defined(SDIO_SUSPEND_RESUME)
+/** Enable Host Sleep configuration */
+int woal_enable_hs(moal_private * priv);
+/** hs active timeout 2 second */
+#define HS_ACTIVE_TIMEOUT (2 * HZ)
+#endif
+
+/** get deep sleep */
+int woal_get_deep_sleep(moal_private * priv, t_u32 * data);
+/** set deep sleep */
+int woal_set_deep_sleep(moal_private * priv, t_u8 wait_option,
+ BOOLEAN bdeep_sleep, t_u16 idletime);
+
+/** Get BSS information */
+mlan_status woal_get_bss_info(moal_private * priv, t_u8 wait_option,
+ mlan_bss_info * bss_info);
+void woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req);
+#ifdef STA_SUPPORT
+void woal_send_disconnect_to_system(moal_private * priv);
+void woal_send_mic_error_event(moal_private * priv, t_u32 event);
+void woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss);
+void woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info);
+/** Get signal information */
+mlan_status woal_get_signal_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_signal * signal);
+#ifdef STA_WEXT
+/** Get mode */
+t_u32 woal_get_mode(moal_private * priv, t_u8 wait_option);
+/** Get data rates */
+mlan_status woal_get_data_rates(moal_private * priv, t_u8 wait_option,
+ moal_802_11_rates * m_rates);
+void woal_send_iwevcustom_event(moal_private * priv, t_s8 * str);
+/** Get statistics information */
+mlan_status woal_get_stats_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_stats * stats);
+/** Get channel list */
+mlan_status woal_get_channel_list(moal_private * priv, t_u8 wait_option,
+ mlan_chan_list * chanlist);
+#endif
+/** Set/Get retry count */
+mlan_status woal_set_get_retry(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get RTS threshold */
+mlan_status woal_set_get_rts(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get fragment threshold */
+mlan_status woal_set_get_frag(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get generic element */
+mlan_status woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie,
+ int *ie_len);
+/** Set/Get TX power */
+mlan_status woal_set_get_tx_power(moal_private * priv, t_u32 action,
+ mlan_power_cfg_t * pwr);
+/** Set/Get power IEEE management */
+mlan_status woal_set_get_power_mgmt(moal_private * priv, t_u32 action,
+ int *disabled, int type);
+/** Get data rate */
+mlan_status woal_set_get_data_rate(moal_private * priv, t_u8 action,
+ mlan_rate_cfg_t * datarate);
+/** Request a network scan */
+mlan_status woal_request_scan(moal_private * priv, t_u8 wait_option,
+ mlan_802_11_ssid * req_ssid);
+/** Set radio on/off */
+int woal_set_radio(moal_private * priv, t_u8 option);
+/** Set region code */
+mlan_status woal_set_region_code(moal_private * priv, char *region);
+/** Set authentication mode */
+mlan_status woal_set_auth_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 auth_mode);
+/** Set encryption mode */
+mlan_status woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 encrypt_mode);
+/** Enable wep key */
+mlan_status woal_enable_wep_key(moal_private * priv, t_u8 wait_option);
+/** Set WPA enable */
+mlan_status woal_set_wpa_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 enable);
+
+/** Find best network to connect */
+mlan_status woal_find_best_network(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Set Ad-Hoc channel */
+mlan_status woal_change_adhoc_chan(moal_private * priv, int channel);
+
+/** Get scan table */
+mlan_status woal_get_scan_table(moal_private * priv, t_u8 wait_option,
+ mlan_scan_resp * scanresp);
+/** Get authentication mode */
+mlan_status woal_get_auth_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * auth_mode);
+/** Get encryption mode */
+mlan_status woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * encrypt_mode);
+/** Get WPA state */
+mlan_status woal_get_wpa_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 * enable);
+#endif /**STA_SUPPORT */
+
+mlan_status woal_set_wapi_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 enable);
+
+/** Initialize priv */
+void woal_init_priv(moal_private * priv, t_u8 wait_option);
+/** Reset interface(s) */
+int woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf);
+/** common ioctl for uap, station */
+int woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req);
+int woal_send_host_packet(struct net_device *dev, struct ifreq *req);
+/** Private command ID to pass mgmt frame */
+#define WOAL_MGMT_FRAME_TX_IOCTL (SIOCDEVPRIVATE + 12)
+
+int woal_get_bss_type(struct net_device *dev, struct ifreq *req);
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_host_command(moal_private * priv, struct iwreq *wrq);
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+mlan_status woal_bss_role_cfg(moal_private * priv, t_u8 action,
+ t_u8 wait_option, t_u8 * bss_role);
+int woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq);
+#endif
+#endif
+#endif
+#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT)
+/** hostcmd ioctl for uap, wifidirect */
+int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req);
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT)
+mlan_status woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option,
+ mlan_ds_remain_chan * pchan);
+mlan_status woal_wifi_direct_mode_cfg(moal_private * priv, t_u16 action,
+ t_u16 * mode);
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef CONFIG_PROC_FS
+/** Initialize proc fs */
+void woal_proc_init(moal_handle * handle);
+/** Clean up proc fs */
+void woal_proc_exit(moal_handle * handle);
+/** Create proc entry */
+void woal_create_proc_entry(moal_private * priv);
+/** Remove proc entry */
+void woal_proc_remove(moal_private * priv);
+/** string to number */
+int woal_string_to_number(char *s);
+#endif
+
+#ifdef PROC_DEBUG
+/** Create debug proc fs */
+void woal_debug_entry(moal_private * priv);
+/** Remove debug proc fs */
+void woal_debug_remove(moal_private * priv);
+#endif /* PROC_DEBUG */
+
+/** check pm info */
+mlan_status woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info);
+
+#ifdef REASSOCIATION
+int woal_reassociation_thread(void *data);
+void woal_reassoc_timer_func(void *context);
+#endif /* REASSOCIATION */
+
+t_void woal_main_work_queue(struct work_struct *work);
+
+int woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+moal_private *woal_add_interface(moal_handle * handle, t_u8 bss_num,
+ t_u8 bss_type);
+void woal_remove_interface(moal_handle * handle, t_u8 bss_index);
+void woal_set_multicast_list(struct net_device *dev);
+mlan_status woal_request_fw(moal_handle * handle);
+
+int woal_11h_channel_check_ioctl(moal_private * priv);
+void woal_cancel_cac_block(moal_private * priv);
+void woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag);
+
+#ifdef STA_SUPPORT
+mlan_status woal_get_powermode(moal_private * priv, int *powermode);
+mlan_status woal_set_scan_type(moal_private * priv, t_u32 scan_type);
+mlan_status woal_set_powermode(moal_private * priv, char *powermode);
+int woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid);
+mlan_status woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg);
+int woal_set_combo_scan(moal_private * priv, char *buf, int length);
+mlan_status woal_get_band(moal_private * priv, int *band);
+mlan_status woal_set_band(moal_private * priv, char *pband);
+mlan_status woal_add_rxfilter(moal_private * priv, char *rxfilter);
+mlan_status woal_remove_rxfilter(moal_private * priv, char *rxfilter);
+mlan_status woal_set_qos_cfg(moal_private * priv, char *qos_cfg);
+int woal_set_sleeppd(moal_private * priv, char *psleeppd);
+mlan_status woal_set_rssi_low_threshold(moal_private * priv, char *rssi);
+mlan_status woal_set_rssi_threshold(moal_private * priv, t_u32 event_id);
+mlan_status woal_set_bg_scan(moal_private * priv, char *buf, int length);
+mlan_status woal_stop_bg_scan(moal_private * priv);
+void woal_reconfig_bgscan(moal_handle * handle);
+#endif
+
+struct tcp_sess *woal_get_tcp_sess(moal_private * priv,
+ t_u32 src_ip, t_u16 src_port,
+ t_u32 dst_ip, t_u16 dst_port);
+void woal_check_tcp_fin(moal_private * priv, struct sk_buff *skb);
+
+#endif /* _MOAL_MAIN_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_priv.c
new file mode 100644
index 000000000000..9a5173ddfb3f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.c
@@ -0,0 +1,6690 @@
+/** @file moal_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ * 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/30/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#include "moal_eth_ioctl.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** Bands supported in Infra mode */
+static t_u8 SupportedInfraBand[] = {
+ BAND_B,
+ BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B, BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A,
+ BAND_AN, BAND_A | BAND_AN,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to destination buffer
+ * @param pos The position for copy
+ * @param src A pointer to source buffer
+ * @param len Length of the source buffer
+ *
+ * @return Number of rates copied
+ */
+static inline int
+woal_copy_rates(t_u8 * dest, int pos, t_u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= MLAN_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+ return pos;
+}
+
+/**
+ * @brief Performs warm reset
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_warm_reset(moal_private * priv)
+{
+ int ret = 0;
+ int intf_num;
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ t_u8 bss_role = MLAN_BSS_ROLE_STA;
+#endif
+#endif
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ ENTER();
+
+ woal_cancel_cac_block(priv);
+
+ /* Reset all interfaces */
+ ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
+
+ /* Initialize private structures */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if (handle->priv[intf_num]->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(handle->priv[intf_num],
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+ }
+
+ /* Restart the firmware */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_WARM_RESET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ kfree(req);
+ goto done;
+ }
+ kfree(req);
+ }
+
+ /* Enable interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ netif_device_attach(handle->priv[intf_num]->netdev);
+ woal_start_queue(handle->priv[intf_num]->netdev);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signal
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_signal(moal_private * priv, struct iwreq *wrq)
+{
+/** Input data size */
+#define IN_DATA_SIZE 2
+/** Output data size */
+#define OUT_DATA_SIZE 12
+ int ret = 0;
+ int in_data[IN_DATA_SIZE];
+ int out_data[OUT_DATA_SIZE];
+ mlan_ds_get_signal signal;
+ int data_length = 0;
+ int buflen = 0;
+
+ ENTER();
+
+ memset(in_data, 0, sizeof(in_data));
+ memset(out_data, 0, sizeof(out_data));
+ buflen = MIN(wrq->u.data.length, IN_DATA_SIZE);
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (sizeof(int) * wrq->u.data.length > sizeof(in_data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(in_data, wrq->u.data.pointer, sizeof(int) * buflen)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ switch (wrq->u.data.length) {
+ case 0: /* No checking, get everything */
+ break;
+ case 2: /* Check subtype range */
+ if (in_data[1] < 1 || in_data[1] > 4) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Fall through */
+ case 1: /* Check type range */
+ if (in_data[0] < 1 || in_data[0] > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int) signal.bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int) signal.bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n", (int) signal.data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n", (int) signal.data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n", (int) signal.bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n", (int) signal.bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n", (int) signal.data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n", (int) signal.data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n", (int) signal.bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n", (int) signal.bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n", (int) signal.data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n", (int) signal.data_nf_avg);
+
+ /* Check type */
+ switch (in_data[0]) {
+ case 0: /* Send everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* RSSI */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_rssi_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: /* SNR */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_snr_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_snr_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_snr_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3: /* NF */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_nf_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_nf_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_nf_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, out_data,
+ wrq->u.data.length * sizeof(out_data[0]))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set DeepSleep mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wreq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_deep_sleep_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ t_u32 deep_sleep = DEEP_SLEEP_OFF;
+ t_u32 data[2];
+ t_u16 idletime = DEEP_SLEEP_IDLE_TIME;
+
+ ENTER();
+
+ if (wrq->u.data.length == 1 || wrq->u.data.length == 2) {
+ if (copy_from_user
+ (&data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ deep_sleep = data[0];
+ if (deep_sleep == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (deep_sleep == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (wrq->u.data.length == 2)
+ idletime = data[1];
+ else
+ idletime = 0;
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, idletime);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EINVAL;
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", deep_sleep);
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (wrq->u.data.length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments %d\n", wrq->u.data.length);
+ LEAVE();
+ return -EINVAL;
+ } else { /* Display Deep Sleep settings */
+ PRINTM(MINFO, "Get Deep Sleep Mode\n");
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
+ LEAVE();
+ return -EFAULT;
+ }
+ if (data[0] == 0)
+ wrq->u.data.length = 1;
+ else
+ wrq->u.data.length = 2;
+ }
+
+ /* Copy the Deep Sleep setting to user */
+ if (copy_to_user
+ (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set/Get Usr 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_htcap_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (((req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg))) == NULL)) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, data_length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.htcap_cfg.htcap = data[0];
+ PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (data_length == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.htcap_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.htcap_cfg.htcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ data_length = 1;
+ cfg_11n->param.htcap_cfg.htcap = 0;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.htcap_cfg.htcap != data[0]) {
+ data_length = 2;
+ data[1] = cfg_11n->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]);
+ PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: htcapinfo:0x%x\n", data[0]);
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wrq->u.data.length = data_length;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable amsdu_aggr_ctrl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_amsdu_aggr_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.length != 0) && (wrq->u.data.length != 1)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 1) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
+ data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_tx_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, data_length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.tx_cfg.httxcap = data[0];
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (data_length == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.tx_cfg.httxcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ data_length = 1;
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.tx_cfg.httxcap != data[0]) {
+ data_length = 2;
+ data[1] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n", data[0]);
+ PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = data_length;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable TX Aggregation
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_prio_tbl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID * 2], i, j;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.pointer == NULL)) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ wrq->u.data.length = MAX_NUM_TID * 2;
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ data[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
+ data[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 16) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ if ((data[i] > 7 && data[i] != 0xff) ||
+ (data[i + 1] > 7 && data[i + 1] != 0xff)) {
+ PRINTM(MERROR, "Invalid priority, valid value 0-7 or 0xff.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA Reject parameters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_addba_reject(moal_private * priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID], ret = 0, i;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ PRINTM(MERROR, "Addba reject moal\n");
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ wrq->u.data.length = MAX_NUM_TID;
+ for (i = 0; i < (wrq->u.data.length); ++i) {
+ data[i] = cfg_11n->param.addba_reject[i];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 8) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0; i < (wrq->u.data.length); ++i) {
+ if (data[i] != 0 && data[i] != 1) {
+ PRINTM(MERROR, "addba reject only takes argument as 0 or 1\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_reject[i] = data[i];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA parameters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_addba_para_updt(moal_private * priv, struct iwreq *wrq)
+{
+ int data[5], ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Add BA parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = cfg_11n->param.addba_param.timeout;
+ data[1] = cfg_11n->param.addba_param.txwinsize;
+ data[2] = cfg_11n->param.addba_param.rxwinsize;
+ data[3] = cfg_11n->param.addba_param.txamsdu;
+ data[4] = cfg_11n->param.addba_param.rxamsdu;
+ PRINTM(MINFO,
+ "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ wrq->u.data.length = 5;
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 5) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
+ PRINTM(MERROR, "Incorrect addba timeout value.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE || data[2] <= 0
+ || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
+ PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.timeout = data[0];
+ cfg_11n->param.addba_param.txwinsize = data[1];
+ cfg_11n->param.addba_param.rxwinsize = data[2];
+ if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
+ PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.txamsdu = data[3];
+ cfg_11n->param.addba_param.rxamsdu = data[4];
+ PRINTM(MINFO,
+ "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ /* Update Add BA parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit buffer size
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_txbuf_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int buf_size;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Tx buffer size from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ PRINTM(MERROR,
+ "Don't support set Tx buffer size after driver loaded!\n");
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf_size = cfg_11n->param.tx_buf_size;
+ if (copy_to_user(wrq->u.data.pointer, &buf_size, sizeof(buf_size))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_hs_cfg(moal_private * priv, struct iwreq *wrq, BOOLEAN invoke_hostcmd)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ds_hs_cfg hscfg;
+ t_u16 action;
+ mlan_bss_info bss_info;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+
+ if (data_length == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ if (data_length >= 1 && data_length <= 3) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* HS config is blocked if HS is already activated */
+ if (data_length &&
+ (data[0] != HOST_SLEEP_CFG_CANCEL || invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Do a GET first if some arguments are not provided */
+ if (data_length >= 1 && data_length < 3) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg);
+ }
+
+ if (data_length)
+ hscfg.conditions = data[0];
+ if (data_length >= 2)
+ hscfg.gpio = data[1];
+ if (data_length == 3)
+ hscfg.gap = data[2];
+
+ if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
+ /* Need to issue an extra IOCTL first to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ data[0] = hscfg.conditions;
+ data[1] = hscfg.gpio;
+ data[2] = hscfg.gap;
+ wrq->u.data.length = 3;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_hs_setpara(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length >= 1 && data_length <= 3) {
+ ret = woal_hs_cfg(priv, wrq, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set inactivity timeout extend
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_inactivity_timeout_ext(moal_private * priv, struct iwreq *wrq)
+{
+ int data[4];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ pmlan_ds_inactivity_to inac_to = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if ((data_length != 0 && data_length != 3 && data_length != 4) ||
+ sizeof(int) * data_length > sizeof(data)) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->action = MLAN_ACT_GET;
+ if (data_length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ inac_to->timeout_unit = data[0];
+ inac_to->unicast_timeout = data[1];
+ inac_to->mcast_timeout = data[2];
+ inac_to->ps_entry_timeout = data[3];
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy back current values regardless of GET/SET */
+ data[0] = inac_to->timeout_unit;
+ data[1] = inac_to->unicast_timeout;
+ data[2] = inac_to->mcast_timeout;
+ data[3] = inac_to->ps_entry_timeout;
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = 4;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get system clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_ecl_sys_clock(moal_private * priv, struct iwreq *wrq)
+{
+ int data[64];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int data_length = wrq->u.data.length;
+ int i = 0;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length)
+ req->action = MLAN_ACT_GET;
+ else if (data_length <= MLAN_MAX_CLK_NUM) {
+ req->action = MLAN_ACT_SET;
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ /* Get configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Current system clock */
+ data[0] = (int) cfg->param.sys_clock.cur_sys_clk;
+ wrq->u.data.length = 1;
+
+ data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Configurable clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int) cfg->param.sys_clock.sys_clk[i];
+ }
+ wrq->u.data.length += data_length;
+
+ /* Get supported clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Supported clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int) cfg->param.sys_clock.sys_clk[i];
+ }
+
+ wrq->u.data.length += data_length;
+
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /* Set configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ cfg->param.sys_clock.sys_clk_num = MIN(MLAN_MAX_CLK_NUM, data_length);
+ for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++) {
+ cfg->param.sys_clock.sys_clk[i] = (t_u16) data[i];
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_band_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ unsigned int i;
+ int data[4];
+ int user_data_len = wrq->u.data.length;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ t_u32 adhoc_chan_bandwidth = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from
+ MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = radio_cfg->param.band_cfg.config_bands; /* Infra Band */
+ data[1] = radio_cfg->param.band_cfg.adhoc_start_band; /* Adhoc Band */
+ data[2] = radio_cfg->param.band_cfg.adhoc_channel; /* Adhoc
+ Channel */
+ wrq->u.data.length = 3;
+ if (radio_cfg->param.band_cfg.adhoc_start_band & BAND_GN
+ || radio_cfg->param.band_cfg.adhoc_start_band & BAND_AN) {
+ data[3] = radio_cfg->param.band_cfg.sec_chan_offset;
+ wrq->u.data.length = 4;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+
+ /* To support only <b/bg/bgn/n> */
+ infra_band = data[0];
+ for (i = 0; i < sizeof(SupportedInfraBand); i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len >= 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ if (user_data_len == 4) {
+ if (!(adhoc_band & (BAND_GN | BAND_AN))) {
+ PRINTM(MERROR,
+ "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ adhoc_chan_bandwidth = data[3];
+ if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW)
+ ) {
+ PRINTM(MERROR,
+ "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ radio_cfg->param.band_cfg.sec_chan_offset = adhoc_chan_bandwidth;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write adapter registers value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_reg_read_write(moal_private * priv, struct iwreq *wrq)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *) req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 3) {
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ reg->param.reg_rw.type = (t_u32) data[0];
+ reg->param.reg_rw.offset = (t_u32) data[1];
+ if (data_length == 3)
+ reg->param.reg_rw.value = (t_u32) data[2];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &reg->param.reg_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_read_eeprom(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *) req->pbuf;
+ reg->sub_command = MLAN_OID_EEPROM_RD;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg->param.rd_eeprom.offset = (t_u16) data[0];
+ reg->param.rd_eeprom.byte_count = (t_u16) data[1];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = reg->param.rd_eeprom.byte_count;
+ if (copy_to_user
+ (wrq->u.data.pointer, reg->param.rd_eeprom.value,
+ MIN(wrq->u.data.length, MAX_EEPROM_DATA))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write device memory value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_mem_read_write(moal_private * priv, struct iwreq *wrq)
+{
+ t_u32 data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *) req->pbuf;
+ reg_mem->sub_command = MLAN_OID_MEM_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 1) {
+ PRINTM(MINFO, "MEM_RW: GET\n");
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 2) {
+ PRINTM(MINFO, "MEM_RW: SET\n");
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg_mem->param.mem_rw.addr = (t_u32) data[0];
+ if (data_length == 2)
+ reg_mem->param.mem_rw.value = (t_u32) data[1];
+
+ PRINTM(MINFO, "MEM_RW: Addr=0x%x, Value=0x%x\n",
+ (int) reg_mem->param.mem_rw.addr, (int) reg_mem->param.mem_rw.value);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &reg_mem->param.mem_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get LOG
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_log(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_get_stats stats;
+ char *buf = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, " GET STATS\n");
+ if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL))) {
+ PRINTM(MERROR, "kmalloc failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ sprintf(buf, "\n"
+ "mcasttxframe %u\n"
+ "failed %u\n"
+ "retry %u\n"
+ "multiretry %u\n"
+ "framedup %u\n"
+ "rtssuccess %u\n"
+ "rtsfailure %u\n"
+ "ackfailure %u\n"
+ "rxfrag %u\n"
+ "mcastrxframe %u\n"
+ "fcserror %u\n"
+ "txframe %u\n"
+ "wepicverrcnt-1 %u\n"
+ "wepicverrcnt-2 %u\n"
+ "wepicverrcnt-3 %u\n"
+ "wepicverrcnt-4 %u\n",
+ stats.mcast_tx_frame,
+ stats.failed,
+ stats.retry,
+ stats.multi_retry,
+ stats.frame_dup,
+ stats.rts_success,
+ stats.rts_failure,
+ stats.ack_failure,
+ stats.rx_frag,
+ stats.mcast_rx_frame,
+ stats.fcs_error,
+ stats.tx_frame,
+ stats.wep_icv_error[0],
+ stats.wep_icv_error[1],
+ stats.wep_icv_error[2], stats.wep_icv_error[3]);
+ wrq->u.data.length = strlen(buf) + 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_deauth(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sockaddr saddr;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ /* Deauth mentioned BSSID */
+ if (copy_from_user(&saddr, wrq->u.data.pointer, sizeof(saddr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) saddr.sa_data)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL))
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_tx_power_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[5], user_data_len;
+ int ret = 0;
+ mlan_bss_info bss_info;
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ memset(data, 0, sizeof(data));
+ user_data_len = wrq->u.data.length;
+
+ if (user_data_len) {
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ switch (user_data_len) {
+ case 1:
+ if (data[0] != 0xFF)
+ ret = -EINVAL;
+ break;
+ case 2:
+ case 4:
+ if (data[0] == 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ if ((unsigned int) data[1] < bss_info.min_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[1], (int) bss_info.min_power_level,
+ (int) bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (user_data_len == 4) {
+ if (data[1] > data[2]) {
+ PRINTM(MERROR, "Min power should be less than maximum!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] < 0) {
+ PRINTM(MERROR, "Step should not less than 0!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if ((unsigned int) data[2] > bss_info.max_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[2], (int) bss_info.min_power_level,
+ (int) bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] > data[2] - data[1]) {
+ PRINTM(MERROR,
+ "Step should not greater than power difference!\n");
+ ret = -EINVAL;
+ break;
+ }
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ if (!user_data_len)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ pcfg->param.power_ext.len = user_data_len;
+ memcpy((t_u8 *) & pcfg->param.power_ext.power_data, (t_u8 *) data,
+ sizeof(data));
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & pcfg->param.power_ext.power_data,
+ sizeof(int) * pcfg->param.power_ext.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = pcfg->param.power_ext.len;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx/Rx data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_txrx_rate(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & rate->param.data_rate,
+ sizeof(int) * 2)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Turn on/off the sdio clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_sdio_clock_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data = 2;
+ /* Initialize the clock state as on */
+ static int clock_state = 1;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ wrq->u.data.length = sizeof(clock_state) / sizeof(int);
+ if (copy_to_user(wrq->u.data.pointer, &clock_state, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ goto done;
+ }
+ switch (data) {
+ case CMD_DISABLED:
+ PRINTM(MINFO, "SDIO clock is turned off\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
+ clock_state = data;
+ break;
+ case CMD_ENABLED:
+ PRINTM(MINFO, "SDIO clock is turned on\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
+ clock_state = data;
+ break;
+ default:
+ ret = -EINVAL;
+ PRINTM(MINFO, "sdioclock: wrong parameter\n");
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_beacon_interval(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int bcn = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bcn, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bcn < MLAN_MIN_BEACON_INTERVAL) ||
+ (bcn > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.bcn_interval = bcn;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & bss->param.bcn_interval,
+ sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_atim_window(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int atim = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&atim, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((atim < 0) || (atim > MLAN_MAX_ATIM_WINDOW)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_ATIM_WINDOW;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.atim_window = atim;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & bss->param.atim_window, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_txrate(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ int rateindex = 0;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ if (copy_from_user(&rateindex, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ if (rateindex == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((rateindex != MLAN_RATE_INDEX_MCS32) &&
+ ((rateindex < 0) || (rateindex > MLAN_RATE_INDEX_MCS15))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = rateindex;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (wrq->u.data.length)
+ priv->rate_index = rateindex;
+ }
+ if (!wrq->u.data.length) {
+ if (rate->param.rate_cfg.is_rate_auto)
+ rateindex = AUTO_RATE;
+ else
+ rateindex = rate->param.rate_cfg.rate;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, &rateindex, sizeof(int))) {
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_regioncode(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int region = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&region, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ if (copy_to_user
+ (wrq->u.data.pointer, &cfg->param.region_code, sizeof(int)))
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_radio(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_bss_info bss_info;
+ int option = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (wrq->u.data.length) {
+ /* Set radio */
+ if (copy_from_user(&option, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8) option))
+ ret = -EFAULT;
+ } else {
+ /* Get radio status */
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ wrq->u.data.length = 1;
+ if (copy_to_user
+ (wrq->u.data.pointer, &bss_info.radio_on,
+ sizeof(bss_info.radio_on))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Get/Set the bit mask of driver debug message control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to wrq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_drv_dbg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[4];
+ int ret = 0;
+
+ ENTER();
+
+ if (!wrq->u.data.length) {
+ data[0] = drvdbg;
+ /* Return the current driver debug bit masks */
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ wrq->u.data.length = 1;
+ } else if (wrq->u.data.length < 3) {
+ /* Get the driver debug bit masks from user */
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ drvdbg = data[0];
+ /* Set the driver debug bit masks into mlan */
+ woal_set_drvdbg(priv, drvdbg);
+ } else {
+ PRINTM(MERROR, "Invalid parameter number\n");
+ goto drvdbgexit;
+ }
+
+ printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+ printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO, (drvdbg & MINFO) ? "X" : "");
+ printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN, (drvdbg & MWARN) ? "X" : "");
+ printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
+ (drvdbg & MENTRY) ? "X" : "");
+#endif
+ printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D, (drvdbg & MIF_D) ? "X" : "");
+ printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D, (drvdbg & MFW_D) ? "X" : "");
+ printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
+ (drvdbg & MEVT_D) ? "X" : "");
+ printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
+ (drvdbg & MCMD_D) ? "X" : "");
+ printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
+ (drvdbg & MDAT_D) ? "X" : "");
+ printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
+ (drvdbg & MIOCTL) ? "X" : "");
+ printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR, (drvdbg & MINTR) ? "X" : "");
+ printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
+ (drvdbg & MEVENT) ? "X" : "");
+ printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND, (drvdbg & MCMND) ? "X" : "");
+ printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA, (drvdbg & MDATA) ? "X" : "");
+ printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
+ (drvdbg & MERROR) ? "X" : "");
+ printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
+ (drvdbg & MFATAL) ? "X" : "");
+ printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG, (drvdbg & MMSG) ? "X" : "");
+
+ drvdbgexit:
+ LEAVE();
+ return ret;
+}
+#endif /* DEBUG_LEVEL1 */
+
+/**
+ * @brief Set/Get QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_qos_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.qos_cfg = (t_u8) data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = (int) cfg->param.qos_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wws_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *wws = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wws = (mlan_ds_misc_cfg *) req->pbuf;
+ wws->sub_command = MLAN_OID_MISC_WWS;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != CMD_DISABLED && data != CMD_ENABLED) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ wws->param.wws_cfg = data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = wws->param.wws_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sleep_pd(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+ (data == 0)
+ || (data == SLEEP_PERIOD_RESERVED_FF)
+ ) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = data;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = pm_cfg->param.sleep_period;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sleep_params_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ mlan_ds_sleep_params *psleep_params = NULL;
+ int data[6] = { 0 }, i;
+#ifdef DEBUG_LEVEL1
+ char err_str[][35] = { {"sleep clock error in ppm"},
+ {"wakeup offset in usec"},
+ {"clock stabilization time in usec"},
+ {"value of reserved for debug"}
+ };
+#endif
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ psleep_params = (pmlan_ds_sleep_params) & pm->param.sleep_params;
+
+ if (wrq->u.data.length == 0) {
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 6) {
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) *
+ wrq->u.data.length)) {
+ /* copy_from_user failed */
+ PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+#define MIN_VAL 0x0000
+#define MAX_VAL 0xFFFF
+ for (i = 0; i < 6; i++) {
+ if ((i == 3) || (i == 4)) {
+ /* These two cases are handled below the loop */
+ continue;
+ }
+ if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
+ PRINTM(MERROR, "Invalid %s (0-65535)!\n", err_str[i]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (data[3] < 0 || data[3] > 2) {
+ PRINTM(MERROR, "Invalid control periodic calibration (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[4] < 0 || data[4] > 2) {
+ PRINTM(MERROR, "Invalid control of external sleep clock (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ psleep_params->error = data[0];
+ psleep_params->offset = data[1];
+ psleep_params->stable_time = data[2];
+ psleep_params->cal_control = data[3];
+ psleep_params->ext_sleep_clk = data[4];
+ psleep_params->reserved = data[5];
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = psleep_params->error;
+ data[1] = psleep_params->offset;
+ data[2] = psleep_params->stable_time;
+ data[3] = psleep_params->cal_control;
+ data[4] = psleep_params->ext_sleep_clk;
+ data[5] = psleep_params->reserved;
+ wrq->u.data.length = 6;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) *
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get user provisioned local power constraint
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_11h_local_pwr_constraint(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ds_11hcfg->param.usr_local_power_constraint = (t_s8) data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ if (req->action == MLAN_ACT_GET) {
+ data = (int) ds_11hcfg->param.usr_local_power_constraint;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_ht_stream_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_11n_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != HT_STREAM_MODE_1X1 && data != HT_STREAM_MODE_2X2) {
+ PRINTM(MINFO, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg->param.stream_cfg = data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int) cfg->param.stream_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get MAC control configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_mac_control_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Validation will be done later */
+ cfg->param.mac_ctrl = data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int) cfg->param.mac_ctrl;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get thermal reading
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_thermal_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ PRINTM(MERROR, "Set is not supported for this command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_MISC_THERMAL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int) cfg->param.thermal;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(REASSOCIATION)
+/**
+ * @brief Set/Get reassociation settings
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_reassoc(moal_private * priv, struct iwreq *wrq)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int data = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data == 0) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ priv->reassoc_required = MFALSE;
+ if (!handle->reassoc_on && handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ } else {
+ handle->reassoc_on |= MBIT(priv->bss_index);
+ priv->reassoc_on = MTRUE;
+ }
+ } else {
+ data = (int) (priv->reassoc_on);
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* REASSOCIATION */
+
+/**
+ * @brief implement WMM enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wmm_enable_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *wmm = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
+
+ if (wrq->u.data.length) {
+ /* Set WMM configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ if (data == CMD_DISABLED)
+ wmm->param.wmm_enable = MFALSE;
+ else
+ wmm->param.wmm_enable = MTRUE;
+ } else {
+ /* Get WMM status */
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &wmm->param.wmm_enable,
+ sizeof(wmm->param.wmm_enable))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11d_enable_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
+ if (wrq->u.data.length) {
+ /* Set 11D configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data == CMD_DISABLED)
+ pcfg_11d->param.enable_11d = MFALSE;
+ else
+ pcfg_11d->param.enable_11d = MTRUE;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &pcfg_11d->param.enable_11d,
+ sizeof(pcfg_11d->param.enable_11d))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D clear chan table command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11d_clr_chan_table(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wps_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+ char buf[8];
+ struct iwreq *wreq = (struct iwreq *) wrq;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, wreq->u.data.pointer,
+ MIN(sizeof(buf) - 1, wreq->u.data.length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (buf[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA passphrase and SSID
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_passphrase(moal_private * priv, struct iwreq *wrq)
+{
+ t_u16 len = 0;
+ static char buf[256];
+ char *begin, *end, *opt;
+ int ret = 0, action = -1, i;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *mac = NULL;
+
+ ENTER();
+
+ if (!wrq->u.data.length || wrq->u.data.length >= sizeof(buf)) {
+ PRINTM(MERROR, "Argument missing or too long for setpassphrase\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[wrq->u.data.length] = '\0';
+
+ /* Parse the buf to get the cmd_action */
+ begin = buf;
+ end = woal_strsep(&begin, ';', '/');
+ if (end)
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ strncpy((char *) sec->param.passphrase.ssid.ssid, end, strlen(end));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid,
+ (int) sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex((t_u8 *) (sec->param.passphrase.psk.pmk.pmk), end,
+ MLAN_PMK_HEXSTR_LENGTH / 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR, "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ strncpy(sec->param.passphrase.psk.passphrase.passphrase, end,
+ sizeof(sec->param.passphrase.psk.passphrase.passphrase));
+ sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int) sec->param.passphrase.psk.passphrase.passphrase_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (action == 0) {
+ memset(buf, 0, sizeof(buf));
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(buf + len, "ssid:");
+ memcpy(buf + len, sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(buf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
+ mac = (t_u8 *) & sec->param.passphrase.bssid;
+ len += sprintf(buf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(buf + len, "%02x:", mac[i]);
+ len += sprintf(buf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(buf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
+ len +=
+ sprintf(buf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(buf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ len +=
+ sprintf(buf + len, "passphrase:%s \n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ }
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, MIN(len, sizeof(buf)))) {
+ PRINTM(MERROR, "Copy to user failed, len %d\n", len);
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = len;
+ }
+
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupp mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_esupp_mode(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & sec->param.esupp_mode,
+ sizeof(int) * 3)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 3;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** AES key length */
+#define AES_KEY_LEN 16
+/**
+ * @brief Adhoc AES control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_adhoc_aes_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ static char buf[256];
+ int ret = 0, action = -1;
+ unsigned int i;
+ t_u8 key_ascii[32];
+ t_u8 key_hex[16];
+ t_u8 *tmp;
+ mlan_bss_info bss_info;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ memset(key_ascii, 0x00, sizeof(key_ascii));
+ memset(key_hex, 0x00, sizeof(key_hex));
+
+ /* Get current BSS information */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.bss_mode != MLAN_BSS_MODE_IBSS ||
+ bss_info.media_connected == MTRUE) {
+ PRINTM(MERROR, "STA is connected or not in IBSS mode.\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (wrq->u.data.length >= sizeof(buf)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[wrq->u.data.length] = '\0';
+
+ if (wrq->u.data.length == 1) {
+ /* Get Adhoc AES Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memcpy(key_hex, sec->param.encrypt_key.key_material,
+ sizeof(key_hex));
+ HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex));
+
+ wrq->u.data.length = sizeof(key_ascii) + 1;
+
+ tmp = key_ascii;
+ for (i = 0; i < sizeof(key_hex); i++)
+ tmp += sprintf((char *) tmp, "%02x", key_hex[i]);
+ } else if (wrq->u.data.length >= 2) {
+ /* Parse the buf to get the cmd_action */
+ action = woal_atox(&buf[0]);
+ if (action < 1 || action > 2) {
+ PRINTM(MERROR, "Invalid action argument %d\n", action);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+
+ if (action == 1) {
+ /* Set Adhoc AES Key */
+ memcpy(key_ascii, &buf[2], sizeof(key_ascii));
+ woal_ascii2hex(key_hex, (char *) key_ascii, sizeof(key_hex));
+ HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex));
+
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ sec->param.encrypt_key.key_flags =
+ KEY_FLAG_SET_TX_KEY | KEY_FLAG_GROUP_KEY;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) bcast_addr,
+ ETH_ALEN);
+ memcpy(sec->param.encrypt_key.key_material, key_hex,
+ sec->param.encrypt_key.key_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (action == 2) {
+ /* Clear Adhoc AES Key */
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) bcast_addr,
+ ETH_ALEN);
+ memset(sec->param.encrypt_key.key_material, 0,
+ sizeof(sec->param.encrypt_key.key_material));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ HEXDUMP("Adhoc AES Key (ASCII)", key_ascii, sizeof(key_ascii));
+ wrq->u.data.length = sizeof(key_ascii);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &key_ascii,
+ sizeof(key_ascii))) {
+ PRINTM(MERROR, "copy_to_user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief arpfilter ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_arp_filter(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;
+ misc->param.gen_ie.len = wrq->u.data.length;
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.gen_ie.ie_data, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get IP address
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq)
+{
+ char buf[IPADDR_MAX_BUF];
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, op_code = 0, data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(buf, 0, IPADDR_MAX_BUF);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+
+ if (data_length <= 1) { /* GET */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user(buf, wrq->u.data.pointer,
+ MIN(IPADDR_MAX_BUF - 1, wrq->u.data.length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Make sure we have the operation argument */
+ if (data_length > 2 && buf[1] != ';') {
+ PRINTM(MERROR, "No operation argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ buf[1] = '\0';
+ }
+ ioctl_req->action = MLAN_ACT_SET;
+ /* only one IP is supported in current firmware */
+ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
+ in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wrq->u.data.length - 2)),
+ misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
+ /* only one IP is supported in current firmware */
+ misc->param.ipaddr_cfg.ip_addr_num = 1;
+ misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
+ }
+ if (woal_atoi(&op_code, &buf[0]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ipaddr_cfg.op_code = (t_u32) op_code;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_IP_ADDR;
+
+ /* Send ioctl to mlan */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ snprintf(buf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
+ misc->param.ipaddr_cfg.op_code,
+ misc->param.ipaddr_cfg.ip_addr[0][0],
+ misc->param.ipaddr_cfg.ip_addr[0][1],
+ misc->param.ipaddr_cfg.ip_addr[0][2],
+ misc->param.ipaddr_cfg.ip_addr[0][3]);
+ wrq->u.data.length = IPADDR_MAX_BUF;
+ if (copy_to_user(wrq->u.data.pointer, buf, IPADDR_MAX_BUF)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming capabilities
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_tx_bf_cap_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+ int bf_cap = 0;
+
+ ENTER();
+
+ if (data_length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
+ req->action = MLAN_ACT_GET;
+ if (data_length) { /* SET */
+ if (copy_from_user(&bf_cap, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ bf_cfg->param.tx_bf_cap = bf_cap;
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bf_cap = bf_cfg->param.tx_bf_cap;
+ if (copy_to_user(wrq->u.data.pointer, &bf_cap, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
+#define MAX_IN_OUT_CHAR 256
+/** Tx BF Global conf argument index */
+#define BF_ENABLE_PARAM 1
+#define SOUND_ENABLE_PARAM 2
+#define FB_TYPE_PARAM 3
+#define SNR_THRESHOLD_PARAM 4
+#define SOUND_INTVL_PARAM 5
+#define BF_MODE_PARAM 6
+#define MAX_TX_BF_GLOBAL_ARGS 6
+#define BF_CFG_ACT_GET 0
+#define BF_CFG_ACT_SET 1
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_tx_bf_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ int bf_action = 0, interval = 0;
+ int snr = 0, i, tmp_val;
+ t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
+ t_u8 *str, *token, *pos;
+ t_u16 action = 0;
+
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ mlan_trigger_sound_args *bf_sound = NULL;
+ mlan_tx_bf_peer_args *tx_bf_peer = NULL;
+ mlan_snr_thr_args *bf_snr = NULL;
+ mlan_bf_periodicity_args *bf_periodicity = NULL;
+ mlan_bf_global_cfg_args *bf_global = NULL;
+
+ ENTER();
+
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+ /* Pointer to corresponding buffer */
+ bf_sound = bf_cfg.body.bf_sound;
+ tx_bf_peer = bf_cfg.body.tx_bf_peer;
+ bf_snr = bf_cfg.body.bf_snr;
+ bf_periodicity = bf_cfg.body.bf_periodicity;
+ bf_global = &bf_cfg.body.bf_global_cfg;
+
+ /* Total characters in buffer */
+ char_count = data_length - 1;
+ memset(buf, 0, sizeof(buf));
+ if (char_count) {
+ if (data_length > sizeof(buf)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, data_length)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (char_count > 1 && buf[1] != ';') {
+ PRINTM(MERROR, "No action argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Replace ';' with NULL in the string to separate args */
+ for (i = 0; i < char_count; i++) {
+ if (buf[i] == ';')
+ buf[i] = '\0';
+ }
+ /* The first byte represents the beamforming action */
+ if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ /* Eliminate action field */
+ token = &buf[2];
+ for (i = 1, str = &buf[2]; token != NULL; i++) {
+ token = strstr(str, " ");
+ pos = str;
+ if (token != NULL) {
+ *token = '\0';
+ str = token + 1;
+ }
+ woal_atoi(&tmp_val, pos);
+ switch (i) {
+ case BF_ENABLE_PARAM:
+ bf_global->bf_enbl = (t_u8) tmp_val;
+ break;
+ case SOUND_ENABLE_PARAM:
+ bf_global->sounding_enbl = (t_u8) tmp_val;
+ break;
+ case FB_TYPE_PARAM:
+ bf_global->fb_type = (t_u8) tmp_val;
+ break;
+ case SNR_THRESHOLD_PARAM:
+ bf_global->snr_threshold = (t_u8) tmp_val;
+ break;
+ case SOUND_INTVL_PARAM:
+ bf_global->sounding_interval = (t_u16) tmp_val;
+ break;
+ case BF_MODE_PARAM:
+ bf_global->bf_mode = (t_u8) tmp_val;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid Argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ /* First arg = 2 BfAction Second arg = 17 MAC "00:50:43:20:BF:64" */
+ if (char_count != 19) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ woal_mac2u8(bf_sound->peer_mac, &buf[2]);
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ /* First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;"
+ Third arg = 1 (min char) TX BF interval 10 (max char) u32
+ maximum value 4294967295 */
+ if (char_count < 19 || char_count > 30) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
+ if (char_count == 19) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ if (woal_atoi(&interval, &buf[20]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_periodicity->interval = interval;
+ }
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ /* Handle only SET operation here First arg = 2 BfAction Second arg
+ = 18 MAC "00:50:43:20:BF:64;" Third arg = 2 enable/disable bf
+ Fourth arg = 2 enable/disable sounding Fifth arg = 1 FB Type */
+ if (char_count != 25 && char_count != 1) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
+ woal_atoi(&tmp_val, &buf[20]);
+ tx_bf_peer->bf_enbl = (t_u8) tmp_val;
+ woal_atoi(&tmp_val, &buf[22]);
+ tx_bf_peer->sounding_enbl = (t_u8) tmp_val;
+ woal_atoi(&tmp_val, &buf[24]);
+ tx_bf_peer->fb_type = (t_u8) tmp_val;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ /* First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;"
+ Third arg = 1/2 SNR u8 - can be 1/2 charerters */
+ if (char_count != 1 && !(char_count == 21 || char_count == 22)) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(bf_snr->peer_mac, &buf[2]);
+ if (woal_atoi(&snr, &buf[20]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_snr->snr = snr;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Save the value */
+ bf_cfg.bf_action = bf_action;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ data_length = 0;
+ memset(buf, 0, sizeof(buf));
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ data_length +=
+ sprintf(buf + data_length, "%d ", (int) bf_global->bf_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int) bf_global->sounding_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d ", (int) bf_global->fb_type);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int) bf_global->snr_threshold);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int) bf_global->sounding_interval);
+ data_length +=
+ sprintf(buf + data_length, "%d ", (int) bf_global->bf_mode);
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_sound->peer_mac[0], bf_sound->peer_mac[1],
+ bf_sound->peer_mac[2], bf_sound->peer_mac[3],
+ bf_sound->peer_mac[4],
+ bf_sound->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ';');
+ data_length += sprintf(buf + data_length, "%d", bf_sound->status);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_periodicity->peer_mac[0],
+ bf_periodicity->peer_mac[1],
+ bf_periodicity->peer_mac[2],
+ bf_periodicity->peer_mac[3],
+ bf_periodicity->peer_mac[4],
+ bf_periodicity->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ data_length +=
+ sprintf(buf + data_length, "%d", bf_periodicity->interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ for (i = 0; i < bf_cfg.no_of_peers; i++) {
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ tx_bf_peer->peer_mac[0],
+ tx_bf_peer->peer_mac[1],
+ tx_bf_peer->peer_mac[2],
+ tx_bf_peer->peer_mac[3],
+ tx_bf_peer->peer_mac[4],
+ tx_bf_peer->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ data_length +=
+ sprintf(buf + data_length, "%d;", tx_bf_peer->bf_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d;",
+ tx_bf_peer->sounding_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d ", tx_bf_peer->fb_type);
+ tx_bf_peer++;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ for (i = 0; i < bf_cfg.no_of_peers; i++) {
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_snr->peer_mac[0], bf_snr->peer_mac[1],
+ bf_snr->peer_mac[2], bf_snr->peer_mac[3],
+ bf_snr->peer_mac[4],
+ bf_snr->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ';');
+ data_length += sprintf(buf + data_length, "%d", bf_snr->snr);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ bf_snr++;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+ buf[data_length] = '\0';
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create a brief scan resp to relay basic BSS info to the app layer
+ *
+ * When the beacon/probe response has not been buffered, use the saved BSS
+ * information available to provide a minimum response for the application
+ * ioctl retrieval routines. Include:
+ * - Timestamp
+ * - Beacon Period
+ * - Capabilities (including WMM Element if available)
+ * - SSID
+ *
+ * @param ppbuffer Output parameter: Buffer used to create basic scan rsp
+ * @param pbss_desc Pointer to a BSS entry in the scan table to create
+ * scan response from for delivery to the application layer
+ *
+ * @return N/A
+ */
+static void
+wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer,
+ BSSDescriptor_t * pbss_desc)
+{
+ t_u8 *ptmp_buf = *ppbuffer;
+ t_u8 tmp_ssid_hdr[2];
+ t_u8 ie_len = 0;
+
+ ENTER();
+
+ if (copy_to_user(ptmp_buf, pbss_desc->time_stamp,
+ sizeof(pbss_desc->time_stamp))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->time_stamp);
+
+ if (copy_to_user(ptmp_buf, &pbss_desc->beacon_period,
+ sizeof(pbss_desc->beacon_period))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->beacon_period);
+
+ if (copy_to_user
+ (ptmp_buf, &pbss_desc->cap_info, sizeof(pbss_desc->cap_info))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->cap_info);
+
+ tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
+ tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
+ if (copy_to_user(ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(tmp_ssid_hdr);
+
+ if (copy_to_user(ptmp_buf, pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += pbss_desc->ssid.ssid_len;
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ ie_len = sizeof(IEEEtypes_Header_t) + pbss_desc->wmm_ie.vend_hdr.len;
+ if (copy_to_user(ptmp_buf, &pbss_desc->wmm_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ ie_len =
+ sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ if (copy_to_user(ptmp_buf, pbss_desc->pwpa_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ ie_len =
+ sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ if (copy_to_user(ptmp_buf, pbss_desc->prsn_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ *ppbuffer = ptmp_buf;
+ LEAVE();
+}
+
+/**
+ * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
+ * Descriptor for inclusion in the ioctl response to the user space
+ * application.
+ *
+ *
+ * @param pbss_desc Pointer to a BSS entry in the scan table to form
+ * scan response from for delivery to the application layer
+ * @param ppbuffer Output parameter: Buffer used to output scan return struct
+ * @param pspace_left Output parameter: Number of bytes available in the
+ * response buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
+ */
+static int
+wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc,
+ t_u8 ** ppbuffer, int *pspace_left)
+{
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+ wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
+ int space_needed;
+ t_u8 *pcurrent;
+ int variable_size;
+
+ const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry);
+
+ ENTER();
+
+ pcurrent = *ppbuffer;
+
+ /* The variable size returned is the stored beacon size */
+ variable_size = pbss_desc->beacon_buf_size;
+
+ /* If we stored a beacon and its size was zero, set the variable size
+ return value to the size of the brief scan response
+ wlan_scan_create_brief_table_entry creates. Also used if we are not
+ configured to store beacons in the first place */
+ if (!variable_size) {
+ variable_size = pbss_desc->ssid.ssid_len + 2;
+ variable_size += (sizeof(pbss_desc->beacon_period)
+ + sizeof(pbss_desc->time_stamp)
+ + sizeof(pbss_desc->cap_info));
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + pbss_desc->wmm_ie.vend_hdr.len);
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + (*(pbss_desc->pwpa_ie)).vend_hdr.len);
+ }
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + (*(pbss_desc->prsn_ie)).ieee_hdr.len);
+ }
+ }
+ }
+
+ space_needed = fixed_size + variable_size;
+
+ PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n",
+ space_needed, *pspace_left);
+
+ if (space_needed >= *pspace_left) {
+ *pspace_left = 0;
+ LEAVE();
+ return -E2BIG;
+ }
+
+ *pspace_left -= space_needed;
+
+ tmp_rsp_entry.fixed_field_length = (sizeof(tmp_rsp_entry)
+ -
+ sizeof(tmp_rsp_entry.fixed_field_length)
+ -
+ sizeof(tmp_rsp_entry.bss_info_length));
+
+ memcpy(tmp_rsp_entry.fixed_fields.bssid,
+ pbss_desc->mac_address, sizeof(prsp_entry->fixed_fields.bssid));
+
+ tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
+ tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
+ tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
+ tmp_rsp_entry.bss_info_length = variable_size;
+
+ /*
+ * Copy fixed fields to user space
+ */
+ if (copy_to_user(pcurrent, &tmp_rsp_entry, fixed_size)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ pcurrent += fixed_size;
+
+ if (pbss_desc->pbeacon_buf) {
+ /*
+ * Copy variable length elements to user space
+ */
+ if (copy_to_user(pcurrent, pbss_desc->pbeacon_buf,
+ pbss_desc->beacon_buf_size)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ pcurrent += pbss_desc->beacon_buf_size;
+ } else {
+ wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
+ }
+
+ *ppbuffer = pcurrent;
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve the scan response/beacon table
+ *
+ * @param wrq A pointer to iwreq structure
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ * @param scan_start argument
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+moal_ret_get_scan_table_ioctl(struct iwreq *wrq,
+ mlan_scan_resp * scan_resp, t_u32 scan_start)
+{
+ pBSSDescriptor_t pbss_desc, scan_table;
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ int ret_code;
+ int ret_len;
+ int space_left;
+ t_u8 *pcurrent;
+ t_u8 *pbuffer_end;
+ t_u32 num_scans_done;
+
+ ENTER();
+
+ num_scans_done = 0;
+ ret_code = MLAN_STATUS_SUCCESS;
+
+ prsp_info = (wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer;
+ pcurrent = (t_u8 *) prsp_info->scan_table_entry_buf;
+
+ pbuffer_end = wrq->u.data.pointer + wrq->u.data.length - 1;
+ space_left = pbuffer_end - pcurrent;
+ scan_table = (BSSDescriptor_t *) (scan_resp->pscan_table);
+
+ PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
+ PRINTM(MINFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
+
+ if (!scan_start) {
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
+
+ /* Use to get current association saved descriptor */
+ pbss_desc = scan_table;
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
+ &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS) {
+ num_scans_done = 1;
+ }
+ } else {
+ scan_start--;
+
+ while (space_left
+ && (scan_start + num_scans_done < scan_resp->num_in_scan_table)
+ && (ret_code == MLAN_STATUS_SUCCESS)) {
+
+ pbss_desc = (scan_table + (scan_start + num_scans_done));
+
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor [%d]\n",
+ scan_start + num_scans_done);
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
+ &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS) {
+ num_scans_done++;
+ }
+ }
+ }
+
+ prsp_info->scan_number = num_scans_done;
+ ret_len = pcurrent - (t_u8 *) wrq->u.data.pointer;
+
+ wrq->u.data.length = ret_len;
+
+ /* Return ret_code (EFAULT or E2BIG) in the case where no scan results were
+ successfully encoded. */
+ LEAVE();
+ return (num_scans_done ? MLAN_STATUS_SUCCESS : ret_code);
+}
+
+/**
+ * @brief Get scan table ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ t_u32 scan_start;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+
+ /* get the whole command from user */
+ if (copy_from_user(&scan_start, wrq->u.data.pointer, sizeof(scan_start))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (scan_start) {
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ } else {
+ scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ status = moal_ret_get_scan_table_ioctl(wrq,
+ &scan->param.scan_resp,
+ scan_start);
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set user scan ext -- Async mode, without wait
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_set_user_scan_ext_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_user_scan_cfg scan_req;
+ ENTER();
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ if (copy_from_user
+ (&scan_req, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(scan_req)))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_req))
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_set_user_scan_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ union iwreq_data wrqu;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) + wrq->u.data.length);
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+
+ if (copy_from_user(scan->param.user_scan.scan_cfg_buf,
+ wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Cmd52 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_cmd52rdwr_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u8 rw = 0, func, data = 0;
+ int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length < 2 || data_length > 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8) buf[0];
+ if (func > 7) {
+ PRINTM(MERROR, "Invalid function number!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ reg = (t_u32) buf[1];
+ if (data_length == 2) {
+ rw = 0; /* CMD52 read */
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ }
+ if (data_length == 3) {
+ rw = 1; /* CMD52 write */
+ data = (t_u8) buf[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func,
+ reg, data);
+ }
+
+ if (!rw) {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ data =
+ sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ reg, &ret);
+ else
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)->
+ func, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg);
+ goto done;
+ }
+ } else {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg);
+ goto done;
+ }
+ }
+
+ buf[0] = data;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cmd53 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_cmd53rdwr_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u8 *buf = NULL;
+ t_u8 rw, func, mode;
+ t_u16 blklen = 0, blknum = 0;
+ int reg = 0, pattern_len = 0, pos = 0, ret = MLAN_STATUS_SUCCESS;
+ t_u32 total_len = 0;
+ t_u8 *data = NULL;
+
+ ENTER();
+
+ if (!(buf = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_KERNEL))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(data = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_KERNEL))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (wrq->u.data.length > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Data lengh is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ rw = buf[0]; /* read/write (0/1) */
+ func = buf[1]; /* func (0/1/2) */
+ reg = buf[5]; /* address */
+ reg = (reg << 8) + buf[4];
+ reg = (reg << 8) + buf[3];
+ reg = (reg << 8) + buf[2];
+ mode = buf[6]; /* byte mode/block mode (0/1) */
+ blklen = buf[8]; /* block size */
+ blklen = (blklen << 8) + buf[7];
+ blknum = buf[10]; /* block number or byte number */
+ blknum = (blknum << 8) + buf[9];
+
+ if (mode != BYTE_MODE)
+ mode = BLOCK_MODE;
+ total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
+ if (total_len > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Total data length is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "CMD53 read/write, func = %d, addr = %#x, mode = %d, "
+ "block size = %d, block(byte) number = %d\n",
+ func, reg, mode, blklen, blknum);
+
+ if (!rw) {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (sdio_readsb
+ (((struct sdio_mmc_card *) priv->phandle->card)->func, data, reg,
+ total_len))
+ PRINTM(MERROR, "sdio_readsb: reading memory 0x%x failed\n", reg);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+
+ if (copy_to_user(wrq->u.data.pointer, data, total_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = total_len;
+ } else {
+ pattern_len = wrq->u.data.length - 11;
+ if (pattern_len > total_len)
+ pattern_len = total_len;
+ memset(data, 0, sizeof(data));
+
+ /* Copy/duplicate the pattern to data buffer */
+ for (pos = 0; pos < total_len; pos++)
+ data[pos] = buf[11 + (pos % pattern_len)];
+
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (sdio_writesb
+ (((struct sdio_mmc_card *) priv->phandle->card)->func, reg, data,
+ total_len))
+ PRINTM(MERROR, "sdio_writesb: writing memory 0x%x failed\n", reg);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ }
+
+ done:
+ if (buf)
+ kfree(buf);
+ if (data)
+ kfree(data);
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief Set SDIO Multi-point aggregation control parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static int
+woal_do_sdio_mpa_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[6], data_length = wrq->u.data.length;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (sizeof(int) * wrq->u.data.length > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(misc, 0, sizeof(mlan_ds_misc_cfg));
+
+ misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ /* Get the values first, then modify these values if user had modified them
+ */
+
+ req->action = MLAN_ACT_GET;
+ if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data_length == 0) {
+ data[0] = misc->param.mpa_ctrl.tx_enable;
+ data[1] = misc->param.mpa_ctrl.rx_enable;
+ data[2] = misc->param.mpa_ctrl.tx_buf_size;
+ data[3] = misc->param.mpa_ctrl.rx_buf_size;
+ data[4] = misc->param.mpa_ctrl.tx_max_ports;
+ data[5] = misc->param.mpa_ctrl.rx_max_ports;
+
+ PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0], data[1],
+ data[2], data[3], data[4], data[5]);
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ goto done;
+ }
+
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ switch (data_length) {
+ case 6:
+ misc->param.mpa_ctrl.rx_max_ports = data[5];
+ case 5:
+ misc->param.mpa_ctrl.tx_max_ports = data[4];
+ case 4:
+ misc->param.mpa_ctrl.rx_buf_size = data[3];
+ case 3:
+ misc->param.mpa_ctrl.tx_buf_size = data[2];
+ case 2:
+ misc->param.mpa_ctrl.rx_enable = data[1];
+ case 1:
+ /* Set cmd */
+ req->action = MLAN_ACT_SET;
+
+ PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0], data[1],
+ data[2], data[3], data[4], data[5]);
+
+ misc->param.mpa_ctrl.tx_enable = data[0];
+ break;
+ default:
+ PRINTM(MERROR, "Default case error\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) !=
+ MLAN_STATUS_SUCCESS)) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief Set/Get scan configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_scan_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int arg_len = 7;
+ int data[arg_len];
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > arg_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) {
+ PRINTM(MERROR, "Invalid argument for scan type\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) {
+ PRINTM(MERROR, "Invalid argument for scan mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[2] < 0) || (data[2] > MAX_PROBES)) {
+ PRINTM(MERROR, "Invalid argument for scan probes\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (((data[3] < 0) || (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[4] < 0) || (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[5] < 0) || (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) {
+ PRINTM(MERROR, "Invalid argument for scan time\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[6] < 0) || (data[6] > 1)) {
+ PRINTM(MERROR, "Invalid argument for extended scan\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ memcpy(&scan->param.scan_cfg, data, sizeof(data));
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ memcpy(data, &scan->param.scan_cfg, sizeof(data));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_ps_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[7], ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int allowed = 3;
+ int i = 3;
+
+ ENTER();
+
+ allowed++; /* For ad-hoc awake period parameter */
+ allowed++; /* For beacon missing timeout parameter */
+ allowed += 2; /* For delay to PS and PS mode parameters */
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > allowed) {
+ ret = -EINVAL;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < PS_NULL_DISABLE)) {
+ PRINTM(MERROR, "Invalid argument for PS null interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM)
+ && (data[1] != MRVDRV_MATCH_CLOSEST_DTIM)
+ && ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM)
+ || (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
+ PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL)
+ && (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
+ PRINTM(MERROR, "Invalid argument for listen interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[i] != SPECIAL_ADHOC_AWAKE_PD) &&
+ ((data[i] < MIN_ADHOC_AWAKE_PD) ||
+ (data[i] > MAX_ADHOC_AWAKE_PD))) {
+ PRINTM(MERROR, "Invalid argument for adhoc awake period\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != DISABLE_BCN_MISS_TO) &&
+ ((data[i] < MIN_BCN_MISS_TO) || (data[i] > MAX_BCN_MISS_TO))) {
+ PRINTM(MERROR, "Invalid argument for beacon miss timeout\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if (wrq->u.data.length < allowed - 1)
+ data[i] = DELAY_TO_PS_UNCHANGED;
+ else if ((data[i] < MIN_DELAY_TO_PS) || (data[i] > MAX_DELAY_TO_PS)) {
+ PRINTM(MERROR, "Invalid argument for delay to PS\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != PS_MODE_UNCHANGED) && (data[i] != PS_MODE_AUTO) &&
+ (data[i] != PS_MODE_POLL) && (data[i] != PS_MODE_NULL)) {
+ PRINTM(MERROR, "Invalid argument for PS mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ req->action = MLAN_ACT_SET;
+ memcpy(&pm_cfg->param.ps_cfg, data,
+ MIN(sizeof(pm_cfg->param.ps_cfg), sizeof(data)));
+ } else
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(data, &pm_cfg->param.ps_cfg,
+ MIN((sizeof(int) * allowed), sizeof(pm_cfg->param.ps_cfg)));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * allowed)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = allowed;
+
+ if (req->action == MLAN_ACT_SET) {
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ pm_cfg->param.ps_mode = 1;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ * Receive a ADDTS command from the application. The command structure
+ * contains a TSPEC and timeout in milliseconds. The timeout is performed
+ * in the firmware after the ADDTS command frame is sent.
+ *
+ * The TSPEC is received in the API as an opaque block. The firmware will
+ * send the entire data block, including the bytes after the TSPEC. This
+ * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
+ * action frame.
+ *
+ * The IOCTL structure contains two return fields:
+ * - The firmware command result, which indicates failure and timeouts
+ * - The IEEE Status code which contains the corresponding value from
+ * any ADDTS response frame received.
+ *
+ * In addition, the opaque TSPEC data block passed in is replaced with the
+ * TSPEC received in the ADDTS response frame. In case of failure, the
+ * AP may modify the TSPEC on return and in the case of success, the
+ * medium time is returned as calculated by the AP. Along with the TSPEC,
+ * any IEs that are sent in the ADDTS response are also returned and can be
+ * parsed using the IOCTL length as an indicator of extra elements.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure or AP negotiation failure via the commandResult field copied
+ * back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_addts_req_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_addts_req_t addts_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
+
+ memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&addts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(addts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.addts.timeout = addts_ioctl.timeout_ms;
+ cfg->param.addts.ie_data_len = (t_u8) addts_ioctl.ie_data_len;
+
+ memcpy(cfg->param.addts.ie_data,
+ addts_ioctl.ie_data, cfg->param.addts.ie_data_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ addts_ioctl.cmd_result = cfg->param.addts.result;
+ addts_ioctl.ieee_status_code = (t_u8) cfg->param.addts.status_code;
+ addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
+
+ memcpy(addts_ioctl.ie_data,
+ cfg->param.addts.ie_data, cfg->param.addts.ie_data_len);
+
+ wrq->u.data.length = (sizeof(addts_ioctl)
+ - sizeof(addts_ioctl.ie_data)
+ + cfg->param.addts.ie_data_len);
+
+ if (copy_to_user(wrq->u.data.pointer, &addts_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ * Receive a DELTS command from the application. The command structure
+ * contains a TSPEC and reason code along with space for a command result
+ * to be returned. The information is packaged is sent to the wlan_cmd.c
+ * firmware command prep and send routines for execution in the firmware.
+ *
+ * The reason code is not used for WMM implementations but is indicated in
+ * the 802.11e specification.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure via the cmd_result field copied back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_delts_req_t struct for this DELTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_delts_req_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_delts_req_t delts_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
+
+ memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&delts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(delts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: DELTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.delts.status_code = (t_u32) delts_ioctl.ieee_reason_code;
+ cfg->param.delts.ie_data_len = (t_u8) delts_ioctl.ie_data_len;
+
+ memcpy(cfg->param.delts.ie_data,
+ delts_ioctl.ie_data, cfg->param.delts.ie_data_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Return the firmware command result back to the application layer */
+ delts_ioctl.cmd_result = cfg->param.delts.result;
+ wrq->u.data.length = sizeof(delts_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &delts_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: DELTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ * Receive a AC Queue configuration command which is used to get, set, or
+ * default the parameters associated with a specific WMM AC Queue.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_config_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_config_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_config *pqcfg = NULL;
+ wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
+
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ pqcfg = (mlan_ds_wmm_queue_config *) & pwmm->param.q_cfg;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qcfg_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(qcfg_ioctl)))) {
+ PRINTM(MERROR, "QCONFIG: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pqcfg->action = qcfg_ioctl.action;
+ pqcfg->access_category = qcfg_ioctl.access_category;
+ pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ qcfg_ioctl.action = pqcfg->action;
+ qcfg_ioctl.access_category = pqcfg->access_category;
+ qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
+ wrq->u.data.length = sizeof(qcfg_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &qcfg_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
+ *
+ * Receive a AC Queue statistics command from the application for a specific
+ * WMM AC. The command can:
+ * - Turn stats on
+ * - Turn stats off
+ * - Collect and clear the stats
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_stats_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_stats_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_stats *pqstats = NULL;
+ wlan_ioctl_wmm_queue_stats_t qstats_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATS;
+
+ memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
+ pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qstats_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(qstats_ioctl)))) {
+ PRINTM(MERROR, "QSTATS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memcpy((void *) pqstats, (void *) &qstats_ioctl, sizeof(qstats_ioctl));
+ PRINTM(MINFO, "QSTATS: IOCTL [%d,%d]\n", qstats_ioctl.action,
+ qstats_ioctl.user_priority);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
+ memcpy((void *) &qstats_ioctl, (void *) pqstats, sizeof(qstats_ioctl));
+ wrq->u.data.length = sizeof(qstats_ioctl);
+
+ if (copy_to_user
+ (wrq->u.data.pointer, &qstats_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ * Return the following information for each WMM AC:
+ * - WMM IE Acm Required
+ * - Firmware Flow Required
+ * - Firmware Flow Established
+ * - Firmware Queue Enabled
+ * - Firmware Delivery Enabled
+ * - Firmware Trigger Enabled
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_status_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
+
+ if (wrq->u.data.length == sizeof(qstatus_ioctl)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
+ memcpy((void *) &qstatus_ioctl, (void *) &pwmm->param.q_status,
+ sizeof(qstatus_ioctl));
+ wrq->u.data.length = sizeof(qstatus_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &qstatus_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM Traffic Streams
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_ts_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_ts_status_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+
+ if (wrq->u.data.length == sizeof(ts_status_ioctl)) {
+ if (copy_from_user(&ts_status_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(ts_status_ioctl)))) {
+ PRINTM(MERROR, "TS_STATUS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
+ pwmm->param.ts_status.tid = ts_status_ioctl.tid;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+ memcpy((void *) &ts_status_ioctl, (void *) &pwmm->param.ts_status,
+ sizeof(ts_status_ioctl));
+ wrq->u.data.length = sizeof(ts_status_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &ts_status_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TS_STATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the By-passed TX packet from upper layer
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the packet
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_bypassed_packet_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sk_buff *skb = NULL;
+ struct ethhdr *eth;
+ t_u16 moreLen = 0, copyLen = 0;
+ ENTER();
+
+#define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)
+
+ copyLen = wrq->u.data.length;
+ moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET
+ + sizeof(mlan_buffer);
+
+ skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
+ if (skb == NULL) {
+ PRINTM(MERROR, "kmalloc no memory !!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, moreLen);
+
+ if (copy_from_user(skb_put(skb, copyLen), wrq->u.data.pointer, copyLen)) {
+ PRINTM(MERROR, "PortBlock: copy from user failed\n");
+ dev_kfree_skb_any(skb);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ eth = (struct ethhdr *) skb->data;
+ eth->h_proto = __constant_htons(eth->h_proto);
+ skb->dev = priv->netdev;
+
+ HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
+
+ woal_hard_start_xmit(skb, priv->netdev);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get auth type
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_auth_type(moal_private * priv, struct iwreq *wrq)
+{
+ int auth_type;
+ t_u32 auth_mode;
+ int ret = 0;
+
+ ENTER();
+ if (wrq->u.data.length == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ auth_type = auth_mode;
+ if (copy_to_user(wrq->u.data.pointer, &auth_type, sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ if (copy_from_user(&auth_type, wrq->u.data.pointer, sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
+ if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
+ (auth_type > MLAN_AUTH_MODE_SHARED))
+ && (auth_type != MLAN_AUTH_MODE_AUTO)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ auth_mode = auth_type;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Port Control mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_port_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&sec->param.port_ctrl_enabled,
+ wrq->u.data.pointer, sizeof(int)) != 0) {
+ PRINTM(MERROR, "port_ctrl:Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ if (copy_to_user(wrq->u.data.pointer, &sec->param.port_ctrl_enabled,
+ sizeof(int))) {
+ PRINTM(MERROR, "port_ctrl:Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(DFS_TESTING_SUPPORT)
+/**
+ * @brief Set/Get DFS Testing settings
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_dfs_testing(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ int ret = 0;
+ int data[4];
+ int data_length = wrq->u.data.length;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (!data_length) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 4) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((unsigned) data[0] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user CAC is 65535 msec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned) data[1] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned) data[3] > 0xFF) {
+ PRINTM(MERROR, "The maximum user fixed channel is 255.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ds_11hcfg->param.dfs_testing.usr_cac_period_msec = (t_u16) data[0];
+ ds_11hcfg->param.dfs_testing.usr_nop_period_sec = (t_u16) data[1];
+ ds_11hcfg->param.dfs_testing.usr_no_chan_change = data[2] ? 1 : 0;
+ ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8) data[3];
+ priv->phandle->cac_period_jiffies = (t_u16) data[0] * HZ / 1000;
+ req->action = MLAN_ACT_SET;
+ } else {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!data_length) {
+ data[0] = ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
+ data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
+ data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
+ data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * 4)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 4;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif /* DFS_SUPPORT && DFS_TESTING_SUPPORT */
+
+/**
+ * @brief Set/Get Mgmt Frame passthru mask
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *mgmt_cfg = NULL;
+ int mask = 0;
+
+ ENTER();
+
+ if (data_length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mgmt_cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+
+ if (data_length) { /* SET */
+ if (copy_from_user(&mask, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mgmt_cfg->param.mgmt_subtype_mask = mask;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mask = mgmt_cfg->param.mgmt_subtype_mask;
+ if (copy_to_user(wrq->u.data.pointer, &mask, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get CFP table codes
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_cfp_code(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data[2];
+ int data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ds_misc_cfp_code *cfp_code = NULL;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc_cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfp_code = &misc_cfg->param.cfp_code;
+ misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfp_code->cfp_code_bg = data[0];
+ if (data_length == 2)
+ cfp_code->cfp_code_a = data[1];
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!data_length) {
+ data[0] = cfp_code->cfp_code_bg;
+ data[1] = cfp_code->cfp_code_a;
+ data_length = 2;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = data_length;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx/Rx antenna
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_tx_rx_ant(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data[2] = { 0 };
+
+ ENTER();
+
+ if (wrq->u.data.length > 2) {
+ PRINTM(MERROR, "Invalid number of argument!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ radio->param.ant_cfg.tx_antenna = data[0];
+ radio->param.ant_cfg.rx_antenna = data[0];
+ if (wrq->u.data.length == 2)
+ radio->param.ant_cfg.rx_antenna = data[1];
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ data[0] = radio->param.ant_cfg.tx_antenna;
+ data[1] = radio->param.ant_cfg.rx_antenna;
+ if (data[0] && data[1] && (data[0] != data[1]))
+ wrq->u.data.length = 2;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *) req;
+ int ret = 0;
+
+ if (!IS_STA_WEXT(cfg80211_wext))
+ return -EOPNOTSUPP;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_wext_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WOAL_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_VERSION: /* Get driver version */
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_VEREXT: /* Get extended driver version */
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_WARMRESET:
+ ret = woal_warm_reset(priv);
+ break;
+ case WOAL_11D_CLR_CHAN_TABLE:
+ ret = woal_11d_clr_chan_table(priv, wrq);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_SET_GET_TXRATE:
+ ret = woal_set_get_txrate(priv, wrq);
+ break;
+ case WOAL_SET_GET_REGIONCODE:
+ ret = woal_set_get_regioncode(priv, wrq);
+ break;
+ case WOAL_SET_RADIO:
+ ret = woal_set_get_radio(priv, wrq);
+ break;
+ case WOAL_WMM_ENABLE:
+ ret = woal_wmm_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_11D_ENABLE:
+ ret = woal_11d_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_GET_QOS_CFG:
+ ret = woal_set_get_qos_cfg(priv, wrq);
+ break;
+#if defined(REASSOCIATION)
+ case WOAL_SET_GET_REASSOC:
+ ret = woal_set_get_reassoc(priv, wrq);
+ break;
+#endif /* REASSOCIATION */
+ case WOAL_TXBUF_CFG:
+ ret = woal_txbuf_cfg(priv, wrq);
+ break;
+ case WOAL_SET_GET_WWS_CFG:
+ ret = woal_wws_cfg(priv, wrq);
+ break;
+ case WOAL_SLEEP_PD:
+ ret = woal_sleep_pd(priv, wrq);
+ break;
+ case WOAL_AUTH_TYPE:
+ ret = woal_auth_type(priv, wrq);
+ break;
+ case WOAL_PORT_CTRL:
+ ret = woal_port_ctrl(priv, wrq);
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case WOAL_SET_GET_BSS_ROLE:
+ ret = woal_set_get_bss_role(priv, wrq);
+ break;
+#endif
+#endif
+ case WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT:
+ ret = woal_set_get_11h_local_pwr_constraint(priv, wrq);
+ break;
+ case WOAL_HT_STREAM_CFG:
+ ret = woal_ht_stream_cfg_ioctl(priv, wrq);
+ break;
+ case WOAL_MAC_CONTROL:
+ ret = woal_mac_control_ioctl(priv, wrq);
+ break;
+ case WOAL_THERMAL:
+ ret = woal_thermal_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_SIXTEEN_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_TX_POWERCFG:
+ ret = woal_tx_power_cfg(priv, wrq);
+ break;
+#ifdef DEBUG_LEVEL1
+ case WOAL_DRV_DBG:
+ ret = woal_drv_dbg(priv, wrq);
+ break;
+#endif
+ case WOAL_BEACON_INTERVAL:
+ ret = woal_beacon_interval(priv, wrq);
+ break;
+ case WOAL_ATIM_WINDOW:
+ ret = woal_atim_window(priv, wrq);
+ break;
+ case WOAL_SIGNAL:
+ ret = woal_get_signal(priv, wrq);
+ break;
+ case WOAL_DEEP_SLEEP:
+ ret = woal_deep_sleep_ioctl(priv, wrq);
+ break;
+ case WOAL_11N_TX_CFG:
+ ret = woal_11n_tx_cfg(priv, wrq);
+ break;
+ case WOAL_11N_AMSDU_AGGR_CTRL:
+ ret = woal_11n_amsdu_aggr_ctrl(priv, wrq);
+ break;
+ case WOAL_11N_HTCAP_CFG:
+ ret = woal_11n_htcap_cfg(priv, wrq);
+ break;
+ case WOAL_PRIO_TBL:
+ ret = woal_11n_prio_tbl(priv, wrq);
+ break;
+ case WOAL_ADDBA_UPDT:
+ ret = woal_addba_para_updt(priv, wrq);
+ break;
+ case WOAL_ADDBA_REJECT:
+ ret = woal_addba_reject(priv, wrq);
+ break;
+ case WOAL_TX_BF_CAP:
+ ret = woal_tx_bf_cap_ioctl(priv, wrq);
+ break;
+ case WOAL_HS_CFG:
+ ret = woal_hs_cfg(priv, wrq, MTRUE);
+ break;
+ case WOAL_HS_SETPARA:
+ ret = woal_hs_setpara(priv, wrq);
+ break;
+ case WOAL_REG_READ_WRITE:
+ ret = woal_reg_read_write(priv, wrq);
+ break;
+ case WOAL_INACTIVITY_TIMEOUT_EXT:
+ ret = woal_inactivity_timeout_ext(priv, wrq);
+ break;
+ case WOAL_SDIO_CLOCK:
+ ret = woal_sdio_clock_ioctl(priv, wrq);
+ break;
+ case WOAL_CMD_52RDWR:
+ ret = woal_cmd52rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_BAND_CFG:
+ ret = woal_band_cfg(priv, wrq);
+ break;
+ case WOAL_SCAN_CFG:
+ ret = woal_set_get_scan_cfg(priv, wrq);
+ break;
+ case WOAL_PS_CFG:
+ ret = woal_set_get_ps_cfg(priv, wrq);
+ break;
+ case WOAL_MEM_READ_WRITE:
+ ret = woal_mem_read_write(priv, wrq);
+ break;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ case WOAL_SDIO_MPA_CTRL:
+ ret = woal_do_sdio_mpa_ctrl(priv, wrq);
+ break;
+#endif
+ case WOAL_SLEEP_PARAMS:
+ ret = woal_sleep_params_ioctl(priv, wrq);
+ break;
+#if defined(DFS_TESTING_SUPPORT)
+ case WOAL_DFS_TESTING:
+ ret = woal_dfs_testing(priv, wrq);
+ break;
+#endif
+ case WOAL_MGMT_FRAME_CTRL:
+ ret = woal_mgmt_frame_passthru_ctrl(priv, wrq);
+ break;
+ case WOAL_CFP_CODE:
+ ret = woal_cfp_code(priv, wrq);
+ break;
+ case WOAL_SET_GET_TX_RX_ANT:
+ ret = woal_set_get_tx_rx_ant(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOALGETLOG:
+ ret = woal_get_log(priv, wrq);
+ break;
+
+ case WOAL_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_PASSPHRASE:
+ ret = woal_passphrase(priv, wrq);
+ break;
+ case WOAL_ADHOC_AES:
+ ret = woal_adhoc_aes_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATUS:
+ ret = woal_wmm_queue_status_ioctl(priv, wrq);
+ break;
+
+ case WOAL_WMM_TS_STATUS:
+ ret = woal_wmm_ts_status_ioctl(priv, wrq);
+ break;
+ case WOAL_IP_ADDRESS:
+ ret = woal_set_get_ip_addr(priv, wrq);
+ break;
+ case WOAL_TX_BF_CFG:
+ ret = woal_tx_bf_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETADDR_GETNONE:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_DEAUTH:
+ ret = woal_deauth(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETNONE_GETTWELVE_CHAR:
+ /*
+ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+ * in flags of iwreq structure, otherwise it will be in
+ * mode member of iwreq structure.
+ */
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_WPS_SESSION:
+ ret = woal_wps_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GET_FOUR_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_DATA_RATE:
+ ret = woal_get_txrx_rate(priv, wrq);
+ break;
+ case WOAL_ESUPP_MODE:
+ ret = woal_get_esupp_mode(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_64_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_ECL_SYS_CLOCK:
+ ret = woal_ecl_sys_clock(priv, wrq);
+ break;
+ }
+
+ break;
+
+ case WOAL_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_ARP_FILTER:
+ ret = woal_arp_filter(priv, wrq);
+ break;
+ case WOAL_SET_INTS_GET_CHARS:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_READ_EEPROM:
+ ret = woal_read_eeprom(priv, wrq);
+ break;
+ }
+ break;
+ case WOAL_SET_GET_2K_BYTES:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_CMD_53RDWR:
+ ret = woal_cmd53rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_USER_SCAN:
+ ret = woal_set_user_scan_ioctl(priv, wrq);
+ break;
+ case WOAL_GET_SCAN_TABLE:
+ ret = woal_get_scan_table_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_USER_SCAN_EXT:
+ ret = woal_set_user_scan_ext_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_ADDTS:
+ ret = woal_wmm_addts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_DELTS:
+ ret = woal_wmm_delts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_CONFIG:
+ ret = woal_wmm_queue_config_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATS:
+ ret = woal_wmm_queue_stats_ioctl(priv, wrq);
+ break;
+ case WOAL_BYPASSED_PACKET:
+ ret = woal_bypassed_packet_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+#ifdef UAP_WEXT
+ case WOAL_FROYO_START:
+ break;
+ case WOAL_FROYO_WL_FW_RELOAD:
+ break;
+ case WOAL_FROYO_STOP:
+ if (IS_UAP_WEXT(cfg80211_wext) && MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ }
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return Wireless mode
+ */
+t_u32
+woal_get_mode(moal_private * priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mode = priv->w_stats.status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ switch (bss->param.bss_mode) {
+ case MLAN_BSS_MODE_INFRA:
+ mode = IW_MODE_INFRA;
+ break;
+ case MLAN_BSS_MODE_IBSS:
+ mode = IW_MODE_ADHOC;
+ break;
+ default:
+ mode = IW_MODE_AUTO;
+ break;
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return mode;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param stats A pointer to mlan_ds_get_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_stats_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_stats * stats)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (stats)
+ memcpy(stats, &info->param.stats, sizeof(mlan_ds_get_stats));
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param m_rates A pointer to moal_802_11_rates structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_data_rates(moal_private * priv, t_u8 wait_option,
+ moal_802_11_rates * m_rates)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_SUPPORTED_RATES;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (m_rates)
+ m_rates->num_of_rates =
+ woal_copy_rates(m_rates->rates, m_rates->num_of_rates,
+ rate->param.rates, MLAN_SUPPORTED_RATES);
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param chan_list A pointer to mlan_chan_list structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_channel_list(moal_private * priv, t_u8 wait_option,
+ mlan_chan_list * chan_list)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (chan_list) {
+ memcpy(chan_list, &bss->param.chanlist, sizeof(mlan_chan_list));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Handle get BSS resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param bss Pointer to mlan_ds_bss structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss)
+{
+ t_u32 mode = 0;
+
+ ENTER();
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_MODE:
+ if (bss->param.bss_mode == MLAN_BSS_MODE_INFRA)
+ mode = IW_MODE_INFRA;
+ else if (bss->param.bss_mode == MLAN_BSS_MODE_IBSS)
+ mode = IW_MODE_ADHOC;
+ else
+ mode = IW_MODE_AUTO;
+ priv->w_stats.status = mode;
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_priv.h
new file mode 100644
index 000000000000..1c24f30502f6
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.h
@@ -0,0 +1,729 @@
+/** @file moal_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ * 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/31/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_PRIV_H_
+#define _WOAL_PRIV_H_
+
+/** Command disabled */
+#define CMD_DISABLED 0
+/** Command enabled */
+#define CMD_ENABLED 1
+/** Command get */
+#define CMD_GET 2
+
+/** 2K bytes */
+#define WOAL_2K_BYTES 2000
+
+/** PRIVATE CMD ID */
+#define WOAL_IOCTL (SIOCIWFIRSTPRIV) /* 0x8BE0 defined in
+ wireless.h */
+
+/** Private command ID to set one int/get word char */
+#define WOAL_SETONEINT_GETWORDCHAR (WOAL_IOCTL + 1)
+/** Private command ID to get version */
+#define WOAL_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_VEREXT 2
+
+/** Private command ID to set/get none */
+#define WOAL_SETNONE_GETNONE (WOAL_IOCTL + 2)
+/** Private command ID for warm reset */
+#define WOAL_WARMRESET 1
+/** Private command ID to clear 11d chan table */
+#define WOAL_11D_CLR_CHAN_TABLE 4
+
+/** Private command ID to set/get sixteen int */
+#define WOAL_SET_GET_SIXTEEN_INT (WOAL_IOCTL + 3)
+/** Private command ID to set/get TX power configurations */
+#define WOAL_TX_POWERCFG 1
+#ifdef DEBUG_LEVEL1
+/** Private command ID to set/get driver debug */
+#define WOAL_DRV_DBG 2
+#endif
+/** Private command ID to set/get beacon interval */
+#define WOAL_BEACON_INTERVAL 3
+/** Private command ID to set/get ATIM window */
+#define WOAL_ATIM_WINDOW 4
+/** Private command ID to get RSSI */
+#define WOAL_SIGNAL 5
+/** Private command ID to set/get Deep Sleep mode */
+#define WOAL_DEEP_SLEEP 7
+/** Private command ID for 11n ht configration */
+#define WOAL_11N_TX_CFG 8
+/** Private command ID for 11n usr ht configration */
+#define WOAL_11N_HTCAP_CFG 9
+/** Private command ID for TX Aggregation */
+#define WOAL_PRIO_TBL 10
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_UPDT 11
+/** Private command ID to set/get Host Sleep configuration */
+#define WOAL_HS_CFG 12
+/** Private command ID to set Host Sleep parameters */
+#define WOAL_HS_SETPARA 13
+/** Private command ID to read/write registers */
+#define WOAL_REG_READ_WRITE 14
+/** Private command ID to set/get band/adhocband */
+#define WOAL_BAND_CFG 15
+/** Private command ID for TX Aggregation */
+#define WOAL_11N_AMSDU_AGGR_CTRL 17
+/** Private command ID to set/get Inactivity timeout */
+#define WOAL_INACTIVITY_TIMEOUT_EXT 18
+/** Private command ID to turn on/off sdio clock */
+#define WOAL_SDIO_CLOCK 19
+/** Private command ID to read/write Command 52 */
+#define WOAL_CMD_52RDWR 20
+/** Private command ID to set/get scan configuration parameter */
+#define WOAL_SCAN_CFG 21
+/** Private command ID to set/get PS configuration parameter */
+#define WOAL_PS_CFG 22
+/** Private command ID to read/write memory */
+#define WOAL_MEM_READ_WRITE 23
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Private command ID to control SDIO MP-A */
+#define WOAL_SDIO_MPA_CTRL 25
+#endif
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_REJECT 27
+/** Private command ID to set/get sleep parameters */
+#define WOAL_SLEEP_PARAMS 28
+/** Private command ID to set/get TX BF capabilities */
+#define WOAL_TX_BF_CAP 31
+#if defined(DFS_TESTING_SUPPORT)
+/** Private command ID to set/get dfs testing settings */
+#define WOAL_DFS_TESTING 33
+#endif
+/** Private command ID to set/get CFP table codes */
+#define WOAL_CFP_CODE 34
+/** Private command ID to set/get tx/rx antenna */
+#define WOAL_SET_GET_TX_RX_ANT 35
+/** Private command ID to set/get management frame passthru mask */
+#define WOAL_MGMT_FRAME_CTRL 36
+
+/** Private command ID to set one int/get one int */
+#define WOAL_SETONEINT_GETONEINT (WOAL_IOCTL + 5)
+/** Private command ID to set/get Tx rate */
+#define WOAL_SET_GET_TXRATE 1
+/** Private command ID to set/get region code */
+#define WOAL_SET_GET_REGIONCODE 2
+/** Private command ID to turn on/off radio */
+#define WOAL_SET_RADIO 3
+/** Private command ID to enable WMM */
+#define WOAL_WMM_ENABLE 4
+/** Private command ID to enable 802.11D */
+#define WOAL_11D_ENABLE 5
+/** Private command ID to set/get QoS configuration */
+#define WOAL_SET_GET_QOS_CFG 7
+#if defined(REASSOCIATION)
+/** Private command ID to set/get reassociation setting */
+#define WOAL_SET_GET_REASSOC 9
+#endif /* REASSOCIATION */
+/** Private command ID for Updating Transmit buffer configration */
+#define WOAL_TXBUF_CFG 10
+/** Private command ID to set/get WWS mode */
+#define WOAL_SET_GET_WWS_CFG 12
+/** Private command ID to set/get sleep period */
+#define WOAL_SLEEP_PD 13
+/** Private command ID to set/get auth type */
+#define WOAL_AUTH_TYPE 18
+/** Private command ID to set/get port control */
+#define WOAL_PORT_CTRL 19
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Private command ID for set/get BSS role */
+#define WOAL_SET_GET_BSS_ROLE 21
+#endif
+#endif
+/** Private command ID for set/get 11h local power constraint */
+#define WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT 22
+/** Private command ID to set/get 11N HT stream configuration */
+#define WOAL_HT_STREAM_CFG 23
+/** Private command ID to set/get MAC control */
+#define WOAL_MAC_CONTROL 24
+/** Private command ID to get thermal value */
+#define WOAL_THERMAL 25
+
+/** Private command ID to get log */
+#define WOALGETLOG (WOAL_IOCTL + 7)
+
+/** Private command ID to set a wext address variable */
+#define WOAL_SETADDR_GETNONE (WOAL_IOCTL + 8)
+/** Private command ID to send deauthentication */
+#define WOAL_DEAUTH 1
+
+/** Private command to get/set 256 chars */
+#define WOAL_SET_GET_256_CHAR (WOAL_IOCTL + 9)
+/** Private command to read/write passphrase */
+#define WOAL_PASSPHRASE 1
+/** Private command to get/set Ad-Hoc AES */
+#define WOAL_ADHOC_AES 2
+/** Private command ID to get WMM queue status */
+#define WOAL_WMM_QUEUE_STATUS 4
+/** Private command ID to get Traffic stream status */
+#define WOAL_WMM_TS_STATUS 5
+#define WOAL_IP_ADDRESS 7
+/** Private command ID to set/get TX bemaforming */
+#define WOAL_TX_BF_CFG 8
+
+/** Get log buffer size */
+#define GETLOG_BUFSIZE 512
+
+/** Private command ID to set none/get twelve chars*/
+#define WOAL_SETNONE_GETTWELVE_CHAR (WOAL_IOCTL + 11)
+/** Private command ID for WPS session */
+#define WOAL_WPS_SESSION 1
+
+/** Private command ID to set none/get four int */
+#define WOAL_SETNONE_GET_FOUR_INT (WOAL_IOCTL + 13)
+/** Private command ID to get data rates */
+#define WOAL_DATA_RATE 1
+/** Private command ID to get E-Supplicant mode */
+#define WOAL_ESUPP_MODE 2
+
+/** Private command to get/set 64 ints */
+#define WOAL_SET_GET_64_INT (WOAL_IOCTL + 15)
+/** Private command ID to set/get ECL system clock */
+#define WOAL_ECL_SYS_CLOCK 1
+
+/** Private command ID for hostcmd */
+#define WOAL_HOST_CMD (WOAL_IOCTL + 17)
+
+/** Private command ID for arpfilter */
+#define WOAL_ARP_FILTER (WOAL_IOCTL + 19)
+
+/** Private command ID to set ints and get chars */
+#define WOAL_SET_INTS_GET_CHARS (WOAL_IOCTL + 21)
+/** Private command ID to read EEPROM data */
+#define WOAL_READ_EEPROM 1
+
+/** Private command ID to set/get 2K bytes */
+#define WOAL_SET_GET_2K_BYTES (WOAL_IOCTL + 23)
+
+/** Private command ID to read/write Command 53 */
+#define WOAL_CMD_53RDWR 2
+
+/** Private command ID for setuserscan */
+#define WOAL_SET_USER_SCAN 3
+/** Private command ID for getscantable */
+#define WOAL_GET_SCAN_TABLE 4
+/** Private command ID for setuserscanext: async without wait */
+#define WOAL_SET_USER_SCAN_EXT 5
+
+/** Private command ID to request ADDTS */
+#define WOAL_WMM_ADDTS 7
+/** Private command ID to request DELTS */
+#define WOAL_WMM_DELTS 8
+/** Private command ID to queue configuration */
+#define WOAL_WMM_QUEUE_CONFIG 9
+/** Private command ID to queue stats */
+#define WOAL_WMM_QUEUE_STATS 10
+/** Private command ID to Bypass auth packet */
+#define WOAL_BYPASSED_PACKET 11
+
+#ifdef UAP_WEXT
+/** The following command IDs are for Froyo app */
+/** Private command ID to start driver */
+#define WOAL_FROYO_START (WOAL_IOCTL + 28)
+/** Private command ID to reload FW */
+#define WOAL_FROYO_WL_FW_RELOAD (WOAL_IOCTL + 29)
+/** Private command ID to stop driver */
+#define WOAL_FROYO_STOP (WOAL_IOCTL + 30)
+#endif
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_private_args[] = {
+ {
+ WOAL_SETONEINT_GETWORDCHAR,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WOAL_VERSION,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {
+ WOAL_VEREXT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "verext"},
+ {
+ WOAL_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_WARMRESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "warmreset"},
+ {
+ WOAL_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WOAL_SET_GET_TXRATE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txratecfg"},
+ {
+ WOAL_SET_GET_REGIONCODE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "regioncode"},
+ {
+ WOAL_SET_RADIO,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "radioctrl"},
+ {
+ WOAL_WMM_ENABLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "wmmcfg"},
+ {
+ WOAL_11D_ENABLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "11dcfg"},
+ {
+ WOAL_11D_CLR_CHAN_TABLE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "11dclrtbl"},
+ {
+ WOAL_SET_GET_QOS_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "qoscfg"},
+ {
+ WOAL_SET_GET_WWS_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "wwscfg"},
+#if defined(REASSOCIATION)
+ {
+ WOAL_SET_GET_REASSOC,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "reassoctrl"},
+#endif
+ {
+ WOAL_TXBUF_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txbufcfg"},
+ {
+ WOAL_SLEEP_PD,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "sleeppd"},
+ {
+ WOAL_AUTH_TYPE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "authtype"},
+ {
+ WOAL_PORT_CTRL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "port_ctrl"},
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ {
+ WOAL_SET_GET_BSS_ROLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "bssrole"},
+#endif
+#endif
+ {
+ WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "powercons"},
+ {
+ WOAL_HT_STREAM_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "htstreamcfg"},
+ {
+ WOAL_MAC_CONTROL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "macctrl"},
+ {
+ WOAL_THERMAL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "thermal"},
+ {
+ WOAL_SET_GET_SIXTEEN_INT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ ""},
+ {
+ WOAL_TX_POWERCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "txpowercfg"},
+#ifdef DEBUG_LEVEL1
+ {
+ WOAL_DRV_DBG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "drvdbg"},
+#endif
+ {
+ WOAL_BEACON_INTERVAL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bcninterval"},
+ {
+ WOAL_ATIM_WINDOW,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "atimwindow"},
+ {
+ WOAL_SIGNAL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getsignal"},
+ {
+ WOAL_DEEP_SLEEP,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "deepsleep",
+ },
+ {
+ WOAL_11N_TX_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "httxcfg"},
+ {
+ WOAL_11N_HTCAP_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "htcapinfo"},
+ {
+ WOAL_PRIO_TBL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "aggrpriotbl"},
+ {
+ WOAL_11N_AMSDU_AGGR_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "amsduaggrctrl"},
+ {
+ WOAL_ADDBA_UPDT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "addbapara"},
+ {
+ WOAL_ADDBA_REJECT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "addbareject"},
+ {
+ WOAL_TX_BF_CAP,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "httxbfcap"},
+ {
+ WOAL_HS_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "hscfg"},
+ {
+ WOAL_HS_SETPARA,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "hssetpara"},
+ {
+ WOAL_REG_READ_WRITE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "regrdwr"},
+ {
+ WOAL_BAND_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bandcfg"},
+ {
+ WOAL_INACTIVITY_TIMEOUT_EXT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "inactivityto"},
+ {
+ WOAL_SDIO_CLOCK,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sdioclock"},
+ {
+ WOAL_CMD_52RDWR,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sdcmd52rw"},
+ {
+ WOAL_SCAN_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "scancfg"},
+ {
+ WOAL_PS_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "pscfg"},
+ {
+ WOAL_MEM_READ_WRITE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "memrdwr"},
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ {
+ WOAL_SDIO_MPA_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "mpactrl"},
+#endif
+ {
+ WOAL_SLEEP_PARAMS,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sleepparams"},
+#if defined(DFS_TESTING_SUPPORT)
+ {
+ WOAL_DFS_TESTING,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "dfstesting"},
+#endif
+ {
+ WOAL_MGMT_FRAME_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "mgmtframectrl"},
+ {
+ WOAL_CFP_CODE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "cfpcode"},
+ {
+ WOAL_SET_GET_TX_RX_ANT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "antcfg"},
+ {
+ WOALGETLOG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+ "getlog"},
+ {
+ WOAL_SETADDR_GETNONE,
+ IW_PRIV_TYPE_ADDR | 1,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_DEAUTH,
+ IW_PRIV_TYPE_ADDR | 1,
+ IW_PRIV_TYPE_NONE,
+ "deauth"},
+ {
+ WOAL_SET_GET_256_CHAR,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ ""},
+ {
+ WOAL_PASSPHRASE,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "passphrase"},
+ {
+ WOAL_ADHOC_AES,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "adhocaes"},
+ {
+ WOAL_WMM_QUEUE_STATUS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "qstatus"},
+ {
+ WOAL_WMM_TS_STATUS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "ts_status"},
+ {
+ WOAL_IP_ADDRESS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "ipaddr"},
+ {
+ WOAL_TX_BF_CFG,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "httxbfcfg"},
+ {
+ WOAL_SETNONE_GETTWELVE_CHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ ""},
+ {
+ WOAL_WPS_SESSION,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "wpssession"},
+ {
+ WOAL_SETNONE_GET_FOUR_INT,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ ""},
+ {
+ WOAL_DATA_RATE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ "getdatarate"},
+ {
+ WOAL_ESUPP_MODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ "esuppmode"},
+ {
+ WOAL_SET_GET_64_INT,
+ IW_PRIV_TYPE_INT | 64,
+ IW_PRIV_TYPE_INT | 64,
+ ""},
+ {
+ WOAL_ECL_SYS_CLOCK,
+ IW_PRIV_TYPE_INT | 64,
+ IW_PRIV_TYPE_INT | 64,
+ "sysclock"},
+ {
+ WOAL_HOST_CMD,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {
+ WOAL_ARP_FILTER,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "arpfilter"},
+ {
+ WOAL_SET_INTS_GET_CHARS,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256,
+ ""},
+ {
+ WOAL_READ_EEPROM,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256,
+ "rdeeprom"},
+ {
+ WOAL_SET_GET_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ ""},
+ {
+ WOAL_CMD_53RDWR,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "sdcmd53rw"},
+ {
+ WOAL_SET_USER_SCAN,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "setuserscan"},
+ {
+ WOAL_GET_SCAN_TABLE,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "getscantable"},
+ {
+ WOAL_SET_USER_SCAN_EXT,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "setuserscanext"},
+ {
+ WOAL_WMM_ADDTS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "addts"},
+ {
+ WOAL_WMM_DELTS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "delts"},
+ {
+ WOAL_WMM_QUEUE_CONFIG,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "qconfig"},
+ {
+ WOAL_WMM_QUEUE_STATS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "qstats"},
+ {
+ WOAL_BYPASSED_PACKET,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "pb_bypass"},
+#ifdef UAP_WEXT
+ {
+ WOAL_FROYO_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "START"},
+ {
+ WOAL_FROYO_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "STOP"},
+ {
+ WOAL_FROYO_WL_FW_RELOAD,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "WL_FW_RELOAD"},
+#endif
+};
+
+/** moal_802_11_rates */
+typedef struct _moal_802_11_rates
+{
+ /** Num of rates */
+ t_u8 num_of_rates;
+ /** Rates */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+} moal_802_11_rates;
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+#endif
+
+#endif /* _WOAL_PRIV_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_proc.c b/drivers/net/wireless/sd8797/mlinux/moal_proc.c
new file mode 100644
index 000000000000..fb7c63a29cab
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_proc.c
@@ -0,0 +1,631 @@
+/** @file moal_proc.c
+ *
+ * @brief This file contains functions for proc file.
+ *
+ * Copyright (C) 2008-2010, 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 "moal_main.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#include "moal_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#define PROC_DIR NULL
+#define MWLAN_PROC_DIR "mwlan/"
+/** Proc top level directory entry */
+struct proc_dir_entry *proc_mwlan = NULL;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#define PROC_DIR &proc_root
+#else
+#define PROC_DIR proc_net
+#endif
+
+#ifdef STA_SUPPORT
+static char *szModes[] = {
+ "Unknown",
+ "Managed",
+ "Ad-hoc",
+ "Auto",
+};
+#endif
+
+extern int drv_mode;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function for info
+ *
+ * @param page Pointer to buffer
+ * @param start Read data starting position
+ * @param offset Offset
+ * @param count Counter
+ * @param eof End of file flag
+ * @param data Data to output
+ *
+ * @return Number of output data
+ */
+static int
+woal_info_proc_read(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct net_device *netdev = data;
+ char fmt[MLAN_MAX_VER_STR_LEN];
+ moal_private *priv = (moal_private *) netdev_priv(netdev);
+#ifdef STA_SUPPORT
+ int i = 0;
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info info;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mcptr = netdev->mc_list;
+ int mc_count = netdev->mc_count;
+#else
+ struct netdev_hw_addr *mcptr = NULL;
+ int mc_count = netdev_mc_count(netdev);
+#endif /* < 2.6.35 */
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ int i = 0;
+#endif /* >= 2.6.29 */
+#endif
+#ifdef UAP_SUPPORT
+ mlan_ds_uap_stats ustats;
+#endif
+
+ ENTER();
+
+ if (offset) {
+ *eof = 1;
+ goto exit;
+ }
+ memset(fmt, 0, sizeof(fmt));
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ p += sprintf(p, "driver_name = " "\"uap\"\n");
+ woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_get_stats(priv, MOAL_PROC_WAIT, &ustats)) {
+ *eof = 1;
+ goto exit;
+ }
+ }
+#endif /* UAP_SUPPORT */
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ woal_get_version(handle, fmt, sizeof(fmt) - 1);
+ memset(&info, 0, sizeof(info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_PROC_WAIT, &info)) {
+ *eof = 1;
+ goto exit;
+ }
+ p += sprintf(p, "driver_name = " "\"wlan\"\n");
+ }
+#endif
+ p += sprintf(p, "driver_version = %s", fmt);
+ p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ p += sprintf(p, "bss_mode = \"WIFIDIRECT-Client\"\n");
+ else
+ p += sprintf(p, "bss_mode = \"WIFIDIRECT-GO\"\n");
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ p += sprintf(p, "bss_mode =\"%s\"\n", szModes[info.bss_mode]);
+#endif
+ p += sprintf(p, "media_state=\"%s\"\n",
+ ((priv->media_connected ==
+ MFALSE) ? "Disconnected" : "Connected"));
+ p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ p += sprintf(p, "multicast_count=\"%d\"\n", mc_count);
+ p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+ p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ info.bssid[0], info.bssid[1],
+ info.bssid[2], info.bssid[3],
+ info.bssid[4], info.bssid[5]);
+ p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
+ p += sprintf(p, "region_code = \"%02x\"\n", (t_u8) info.region_code);
+
+ /*
+ * Put out the multicast list
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ for (i = 0; i < netdev->mc_count; i++) {
+ p += sprintf(p,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i,
+ mcptr->dmi_addr[0], mcptr->dmi_addr[1],
+ mcptr->dmi_addr[2], mcptr->dmi_addr[3],
+ mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
+
+ mcptr = mcptr->next;
+ }
+#else
+ netdev_for_each_mc_addr(mcptr, netdev)
+ p += sprintf(p,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i++,
+ mcptr->addr[0], mcptr->addr[1],
+ mcptr->addr[2], mcptr->addr[3],
+ mcptr->addr[4], mcptr->addr[5]);
+#endif /* < 2.6.35 */
+ }
+#endif
+ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+ p += sprintf(p, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ p += sprintf(p, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped(netdev_get_tx_queue(netdev, 0))) ?
+ "stopped" : "started"));
+ }
+#else
+ p += sprintf(p, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started"));
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ p += sprintf(p, "tkip_mic_failures = %u\n", ustats.tkip_mic_failures);
+ p += sprintf(p, "ccmp_decrypt_errors = %u\n",
+ ustats.ccmp_decrypt_errors);
+ p += sprintf(p, "wep_undecryptable_count = %u\n",
+ ustats.wep_undecryptable_count);
+ p += sprintf(p, "wep_icv_error_count = %u\n",
+ ustats.wep_icv_error_count);
+ p += sprintf(p, "decrypt_failure_count = %u\n",
+ ustats.decrypt_failure_count);
+ p += sprintf(p, "mcast_tx_count = %u\n", ustats.mcast_tx_count);
+ p += sprintf(p, "failed_count = %u\n", ustats.failed_count);
+ p += sprintf(p, "retry_count = %u\n", ustats.retry_count);
+ p += sprintf(p, "multiple_retry_count = %u\n",
+ ustats.multi_retry_count);
+ p += sprintf(p, "frame_duplicate_count = %u\n", ustats.frame_dup_count);
+ p += sprintf(p, "rts_success_count = %u\n", ustats.rts_success_count);
+ p += sprintf(p, "rts_failure_count = %u\n", ustats.rts_failure_count);
+ p += sprintf(p, "ack_failure_count = %u\n", ustats.ack_failure_count);
+ p += sprintf(p, "rx_fragment_count = %u\n", ustats.rx_fragment_count);
+ p += sprintf(p, "mcast_rx_frame_count = %u\n",
+ ustats.mcast_rx_frame_count);
+ p += sprintf(p, "fcs_error_count = %u\n", ustats.fcs_error_count);
+ p += sprintf(p, "tx_frame_count = %u\n", ustats.tx_frame_count);
+ p += sprintf(p, "rsna_tkip_cm_invoked = %u\n",
+ ustats.rsna_tkip_cm_invoked);
+ p += sprintf(p, "rsna_4way_hshk_failures = %u\n",
+ ustats.rsna_4way_hshk_failures);
+ }
+#endif /* UAP_SUPPORT */
+ exit:
+ LEAVE();
+ return (p - page);
+}
+
+#define CMD52_STR_LEN 50
+/*
+ * @brief Parse cmd52 string
+ *
+ * @param buffer A pointer user buffer
+ * @param len Length user buffer
+ * @param func Parsed func number
+ * @param reg Parsed reg value
+ * @param val Parsed value to set
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+parse_cmd52_string(const char __user * buffer, size_t len, int *func, int *reg,
+ int *val)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ char *string = NULL;
+ char *pos = NULL;
+
+ ENTER();
+
+ string = (char *) kmalloc(CMD52_STR_LEN, GFP_KERNEL);
+ memset(string, 0, CMD52_STR_LEN);
+ memcpy(string, buffer + strlen("sdcmd52rw="), len - strlen("sdcmd52rw="));
+ string = strstrip(string);
+
+ *func = -1;
+ *reg = -1;
+ *val = -1;
+
+ /* Get func */
+ pos = strsep(&string, " \t");
+ if (pos) {
+ *func = woal_string_to_number(pos);
+ }
+
+ /* Get reg */
+ pos = strsep(&string, " \t");
+ if (pos) {
+ *reg = woal_string_to_number(pos);
+ }
+
+ /* Get val (optional) */
+ pos = strsep(&string, " \t");
+ if (pos) {
+ *val = woal_string_to_number(pos);
+ }
+ if (string)
+ kfree(string);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief config proc write function
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param cnt data number to write
+ * @param data data to write
+ * @return number of data
+ */
+static int
+woal_config_write(struct file *f, const char *buf, unsigned long cnt,
+ void *data)
+{
+ char databuf[101];
+ char *line;
+ t_u32 config_data = 0;
+ moal_handle *handle = (moal_handle *) data;
+ int func, reg, val;
+
+ ENTER();
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+
+ if (cnt >= sizeof(databuf)) {
+ MODULE_PUT;
+ LEAVE();
+ return (int) cnt;
+ }
+ memset(databuf, 0, sizeof(databuf));
+ if (copy_from_user(databuf, buf, cnt)) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+ line = databuf;
+ if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) {
+ line += strlen("soft_reset") + 1;
+ config_data = (t_u32) woal_string_to_number(line);
+ PRINTM(MINFO, "soft_reset: %d\n", (int) config_data);
+ if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS) {
+ handle->hardware_status = HardwareStatusReset;
+ } else {
+ PRINTM(MERROR, "Could not perform soft reset\n");
+ }
+ }
+ if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) {
+ line += strlen("drv_mode") + 1;
+ config_data = (t_u32) woal_string_to_number(line);
+ PRINTM(MINFO, "drv_mode: %d\n", (int) config_data);
+ if (config_data != (t_u32) drv_mode)
+ if (woal_switch_drv_mode(handle, config_data) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not switch drv mode\n");
+ }
+ }
+ if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw="))) {
+ parse_cmd52_string(databuf, (size_t) cnt, &func, &reg, &val);
+ woal_sdio_read_write_cmd52(handle, func, reg, val);
+ }
+ MODULE_PUT;
+ LEAVE();
+ return (int) cnt;
+}
+
+/**
+ * @brief config proc read function
+ *
+ * @param page pointer to buffer
+ * @param s read data starting position
+ * @param off offset
+ * @param cnt counter
+ * @param eof end of file flag
+ * @param data data to output
+ * @return number of output data
+ */
+static int
+woal_config_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
+{
+ char *p = page;
+ moal_handle *handle = (moal_handle *) data;
+
+ ENTER();
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+ p += sprintf(p, "hardware_status=%d\n", (int) handle->hardware_status);
+ p += sprintf(p, "netlink_num=%d\n", (int) handle->netlink_num);
+ p += sprintf(p, "drv_mode=%d\n", (int) drv_mode);
+ p += sprintf(p, "sdcmd52rw=%d 0x%0x 0x%02X\n", handle->cmd52_func,
+ handle->cmd52_reg, handle->cmd52_val);
+ MODULE_PUT;
+ LEAVE();
+ return p - page;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Convert string to number
+ *
+ * @param s Pointer to numbered string
+ *
+ * @return Converted number from string s
+ */
+int
+woal_string_to_number(char *s)
+{
+ int r = 0;
+ int base = 0;
+ int pn = 1;
+
+ if (!strncmp(s, "-", 1)) {
+ pn = -1;
+ s++;
+ }
+ if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
+ base = 16;
+ s += 2;
+ } else
+ base = 10;
+
+ for (s = s; *s; s++) {
+ if ((*s >= '0') && (*s <= '9'))
+ r = (r * base) + (*s - '0');
+ else if ((*s >= 'A') && (*s <= 'F'))
+ r = (r * base) + (*s - 'A' + 10);
+ else if ((*s >= 'a') && (*s <= 'f'))
+ r = (r * base) + (*s - 'a' + 10);
+ else
+ break;
+ }
+
+ return (r * pn);
+}
+
+/**
+ * @brief Create the top level proc directory
+ *
+ * @param handle Pointer to woal_handle
+ *
+ * @return N/A
+ */
+void
+woal_proc_init(moal_handle * handle)
+{
+ struct proc_dir_entry *r;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+ struct proc_dir_entry *pde = PROC_DIR;
+#endif
+ char config_proc_dir[20];
+
+ ENTER();
+
+ PRINTM(MINFO, "Create Proc Interface\n");
+ if (!handle->proc_mwlan) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+ /* Check if directory already exists */
+ for (pde = pde->subdir; pde; pde = pde->next) {
+ if (pde->namelen && !strcmp("mwlan", pde->name)) {
+ /* Directory exists */
+ PRINTM(MWARN, "proc interface already exists!\n");
+ handle->proc_mwlan = pde;
+ break;
+ }
+ }
+ if (pde == NULL) {
+ handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!handle->proc_mwlan)
+ PRINTM(MERROR, "Cannot create proc interface!\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ else
+ atomic_set(&handle->proc_mwlan->count, 1);
+#endif
+ }
+#else
+ if (!proc_mwlan) {
+ handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!handle->proc_mwlan) {
+ PRINTM(MERROR, "Cannot create proc interface!\n");
+ }
+ } else {
+ handle->proc_mwlan = proc_mwlan;
+ }
+#endif
+ if (handle->proc_mwlan) {
+ if (handle->handle_idx)
+ sprintf(config_proc_dir, "config%d", handle->handle_idx);
+ else
+ strcpy(config_proc_dir, "config");
+
+ r = create_proc_entry(config_proc_dir, 0644, handle->proc_mwlan);
+
+ if (r) {
+ r->data = handle;
+ r->read_proc = woal_config_read;
+ r->write_proc = woal_config_write;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ r->owner = THIS_MODULE;
+#endif
+ } else
+ PRINTM(MMSG, "Fail to create proc config\n");
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+ proc_mwlan = handle->proc_mwlan;
+#endif
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove the top level proc directory
+ *
+ * @param handle pointer moal_handle
+ *
+ * @return N/A
+ */
+void
+woal_proc_exit(moal_handle * handle)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Remove Proc Interface\n");
+ if (handle->proc_mwlan) {
+ char config_proc_dir[20];
+ if (handle->handle_idx)
+ sprintf(config_proc_dir, "config%d", handle->handle_idx);
+ else
+ strcpy(config_proc_dir, "config");
+ remove_proc_entry(config_proc_dir, handle->proc_mwlan);
+
+ /* Remove only if we are the only instance using this */
+ if (atomic_read(&(handle->proc_mwlan->count)) > 1) {
+ PRINTM(MWARN, "More than one interface using proc!\n");
+ } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ atomic_dec(&(handle->proc_mwlan->count));
+#endif
+ remove_proc_entry("mwlan", PROC_DIR);
+ handle->proc_mwlan = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+ proc_mwlan = NULL;
+#endif
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Create proc file for interface
+ *
+ * @param priv pointer moal_private
+ *
+ * @return N/A
+ */
+void
+woal_create_proc_entry(moal_private * priv)
+{
+ struct net_device *dev = priv->netdev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+ char proc_dir_name[20];
+#endif
+
+ ENTER();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+ if (!priv->proc_entry) {
+ memset(proc_dir_name, 0, sizeof(proc_dir_name));
+ strcpy(proc_dir_name, MWLAN_PROC_DIR);
+ strcat(proc_dir_name, dev->name);
+ /* Try to create mwlan/mlanX first */
+ priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR);
+ if (priv->proc_entry) {
+ /* Success. Continue normally */
+ if (!priv->phandle->proc_mwlan) {
+ priv->phandle->proc_mwlan = priv->proc_entry->parent;
+ }
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+ } else {
+ /* Failure. mwlan may not exist. Try to create that first */
+ priv->phandle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!priv->phandle->proc_mwlan) {
+ /* Failure. Something broken */
+ LEAVE();
+ return;
+ } else {
+ /* Success. Now retry creating mlanX */
+ priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR);
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+ }
+ }
+#else
+ if (priv->phandle->proc_mwlan && !priv->proc_entry) {
+ priv->proc_entry = proc_mkdir(dev->name, priv->phandle->proc_mwlan);
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+#endif
+ strcpy(priv->proc_entry_name, dev->name);
+ if (priv->proc_entry) {
+ create_proc_read_entry("info", 0, priv->proc_entry,
+ woal_info_proc_read, dev);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv Pointer moal_private
+ *
+ * @return N/A
+ */
+void
+woal_proc_remove(moal_private * priv)
+{
+ ENTER();
+ if (priv->phandle->proc_mwlan && priv->proc_entry) {
+ remove_proc_entry("info", priv->proc_entry);
+ remove_proc_entry(priv->proc_entry_name, priv->phandle->proc_mwlan);
+ atomic_dec(&(priv->phandle->proc_mwlan->count));
+ priv->proc_entry = NULL;
+ }
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio.h b/drivers/net/wireless/sd8797/mlinux/moal_sdio.h
new file mode 100644
index 000000000000..5a5bc2c3718c
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio.h
@@ -0,0 +1,140 @@
+/** @file moal_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ * 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:
+****************************************************/
+
+#ifndef _MOAL_SDIO_H
+#define _MOAL_SDIO_H
+
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include "moal_main.h"
+
+#ifndef BLOCK_MODE
+/** Block mode */
+#define BLOCK_MODE 1
+#endif
+
+#ifndef BYTE_MODE
+/** Byte Mode */
+#define BYTE_MODE 0
+#endif
+
+#ifndef FIXED_ADDRESS
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+#endif
+
+/** SD8797 chip revision ID */
+#define SD8797_A0 0x00
+#define SD8797_B0 0x10
+
+#define SD8797_A0_FW_NAME "mrvl/sd8797_uapsta_a0.bin"
+#define SD8797_B0_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifdef STA_SUPPORT
+/** Default firmware name */
+
+#define DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifndef DEFAULT_FW_NAME
+#define DEFAULT_FW_NAME ""
+#endif
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+/** Default firmware name */
+
+#define DEFAULT_AP_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifndef DEFAULT_AP_FW_NAME
+#define DEFAULT_AP_FW_NAME ""
+#endif
+#endif /* UAP_SUPPORT */
+
+/** Default firmaware name */
+
+#define DEFAULT_AP_STA_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifndef DEFAULT_AP_STA_FW_NAME
+#define DEFAULT_AP_STA_FW_NAME ""
+#endif
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** Function to write register */
+mlan_status woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data);
+/** Function to read register */
+mlan_status woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data);
+/** Function to write data to IO memory */
+mlan_status woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf,
+ t_u32 port, t_u32 timeout);
+/** Function to read data from IO memory */
+mlan_status woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf,
+ t_u32 port, t_u32 timeout);
+
+/** Register to bus driver function */
+mlan_status woal_bus_register(void);
+/** Unregister from bus driver function */
+void woal_bus_unregister(void);
+
+/** Register device function */
+mlan_status woal_register_dev(moal_handle * handle);
+/** Unregister device function */
+void woal_unregister_dev(moal_handle * handle);
+
+int woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option);
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_FUNC_SUSPENDED
+/** Notify SDIO bus driver that WLAN is suspended */
+void woal_wlan_is_suspended(moal_handle * handle);
+#endif
+/** SDIO Suspend */
+int woal_sdio_suspend(struct device *dev);
+/** SDIO Resume */
+int woal_sdio_resume(struct device *dev);
+#endif /* SDIO_SUSPEND_RESUME */
+
+/** Structure: SDIO MMC card */
+struct sdio_mmc_card
+{
+ /** sdio_func structure pointer */
+ struct sdio_func *func;
+ /** moal_handle structure pointer */
+ moal_handle *handle;
+ /** saved host clock value */
+ unsigned int host_clock;
+};
+
+/** cmd52 read write */
+int woal_sdio_read_write_cmd52(moal_handle * handle, int func, int reg,
+ int val);
+
+#endif /* _MOAL_SDIO_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
new file mode 100644
index 000000000000..f09f33e6435d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
@@ -0,0 +1,734 @@
+/** @file moal_sdio_mmc.c
+ *
+ * @brief This file contains SDIO MMC IF (interface) module
+ * related functions.
+ *
+ * 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:
+ 02/25/09: Initial creation -
+ This file supports SDIO MMC only
+****************************************************/
+
+#include <linux/firmware.h>
+
+#include "moal_sdio.h"
+
+/** define marvell vendor id */
+#define MARVELL_VENDOR_ID 0x02df
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+#ifdef SDIO_SUSPEND_RESUME
+/** PM keep power */
+extern int pm_keep_power;
+#endif
+
+/** Device ID for SD8797 */
+#define SD_DEVICE_ID_8797 (0x9129)
+
+/** WLAN IDs */
+static const struct sdio_device_id wlan_ids[] = {
+ {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8797)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(sdio, wlan_ids);
+
+int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
+void woal_sdio_remove(struct sdio_func *func);
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+int woal_sdio_suspend(struct device *dev);
+int woal_sdio_resume(struct device *dev);
+
+static struct dev_pm_ops wlan_sdio_pm_ops = {
+ .suspend = woal_sdio_suspend,
+ .resume = woal_sdio_resume,
+};
+#endif
+#endif
+static struct sdio_driver wlan_sdio = {
+ .name = "wlan_sdio",
+ .id_table = wlan_ids,
+ .probe = woal_sdio_probe,
+ .remove = woal_sdio_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ .drv = {
+ .owner = THIS_MODULE,
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ .pm = &wlan_sdio_pm_ops,
+#endif
+#endif
+ }
+#else
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ .drv = {
+ .pm = &wlan_sdio_pm_ops,
+ }
+#endif
+#endif
+#endif
+};
+
+/********************************************************
+ Local Functions
+********************************************************/
+/** @brief This function dump the sdio register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @return N/A
+ */
+void
+woal_dump_sdio_reg(moal_handle * handle)
+{
+ int ret = 0;
+ t_u8 data;
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) handle->card)->func, 0x05,
+ &ret);
+ PRINTM(MMSG, "fun0: reg 0x05=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) handle->card)->func, 0x04,
+ &ret);
+ PRINTM(MMSG, "fun0: reg 0x04=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x03, &ret);
+ PRINTM(MMSG, "fun1: reg 0x03=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x04, &ret);
+ PRINTM(MMSG, "fun1: reg 0x04=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x05, &ret);
+ PRINTM(MMSG, "fun1: reg 0x05=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x60, &ret);
+ PRINTM(MMSG, "fun1: reg 0x60=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x61, &ret);
+ PRINTM(MMSG, "fun1: reg 0x61=0x%x ret=%d\n", data, ret);
+ return;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function handles the interrupt.
+ *
+ * @param func A pointer to the sdio_func structure
+ * @return N/A
+ */
+static void
+woal_sdio_interrupt(struct sdio_func *func)
+{
+ moal_handle *handle;
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->handle) {
+ PRINTM(MINFO,
+ "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n",
+ func, card);
+ LEAVE();
+ return;
+ }
+ handle = card->handle;
+
+ PRINTM(MINFO, "*** IN SDIO IRQ ***\n");
+ woal_interrupt(handle);
+
+ LEAVE();
+}
+
+/** @brief This function handles client driver probe.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @param id A pointer to sdio_device_id structure.
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code
+ */
+int
+woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+ func->vendor, func->device, func->class, func->num);
+
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ if (!card) {
+ PRINTM(MFATAL, "Failed to allocate memory in probe function!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ card->func = func;
+
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ /* The byte mode patch is available in kernel MMC driver which fixes one
+ issue in MP-A transfer. bit1: use func->cur_blksize for byte mode */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ /* wait for chip fully wake up */
+ if (!func->enable_timeout)
+ func->enable_timeout = 200;
+#endif
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret) {
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ kfree(card);
+ PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+ LEAVE();
+ return -EIO;
+ }
+ sdio_release_host(func);
+ if (NULL == woal_add_card(card)) {
+ PRINTM(MERROR, "woal_add_card failed\n");
+ kfree(card);
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver remove.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @return N/A
+ */
+void
+woal_sdio_remove(struct sdio_func *func)
+{
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ PRINTM(MINFO, "SDIO func=%d\n", func->num);
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ woal_remove_card(card);
+ kfree(card);
+ }
+ }
+
+ LEAVE();
+}
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+#ifdef MMC_PM_FUNC_SUSPENDED
+/** @brief This function tells lower driver that WLAN is suspended
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @return N/A
+ */
+void
+woal_wlan_is_suspended(moal_handle * handle)
+{
+ ENTER();
+ if (handle->suspend_notify_req == MTRUE) {
+ handle->is_suspended = MTRUE;
+ sdio_func_suspended(((struct sdio_mmc_card *) handle->card)->func);
+ }
+ LEAVE();
+}
+#endif
+
+/** @brief This function handles client driver suspend
+ *
+ * @param dev A pointer to device structure
+ * @return MLAN_STATUS_SUCCESS or error code
+ */
+int
+woal_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ mmc_pm_flag_t pm_flags = 0;
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ int i;
+ int ret = MLAN_STATUS_SUCCESS;
+ int hs_actived = 0;
+ mlan_ds_ps_info pm_info;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n");
+ if (func) {
+ pm_flags = sdio_get_host_pm_caps(func);
+ PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
+ pm_flags);
+ if (!(pm_flags & MMC_PM_KEEP_POWER)) {
+ PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n",
+ sdio_func_id(func));
+ LEAVE();
+ return -ENOSYS;
+ }
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR, "sdio_func is not specified\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ handle = cardp->handle;
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MWARN, "Device already suspended\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ handle->suspend_fail = MFALSE;
+ memset(&pm_info, 0, sizeof(pm_info));
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), &pm_info)) {
+ if (pm_info.is_suspend_allowed == MFALSE) {
+ PRINTM(MMSG, "suspend not allowed!");
+ ret = -EBUSY;
+ goto done;
+ }
+ }
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_detach(handle->priv[i]->netdev);
+
+ if (pm_keep_power) {
+ /* Enable the Host Sleep */
+#ifdef MMC_PM_FUNC_SUSPENDED
+ handle->suspend_notify_req = MTRUE;
+#endif
+ hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+#ifdef MMC_PM_FUNC_SUSPENDED
+ handle->suspend_notify_req = MFALSE;
+#endif
+ if (hs_actived) {
+#ifdef MMC_PM_SKIP_RESUME_PROBE
+ PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER and "
+ "MMC_PM_SKIP_RESUME_PROBE\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER |
+ MMC_PM_SKIP_RESUME_PROBE);
+#else
+ PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+#endif
+ } else {
+ PRINTM(MMSG, "HS not actived, suspend fail!");
+ ret = -EBUSY;
+ goto done;
+ }
+ }
+
+ /* Indicate device suspended */
+ handle->is_suspended = MTRUE;
+ done:
+ PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n");
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver resume
+ *
+ * @param dev A pointer to device structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+int
+woal_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ mmc_pm_flag_t pm_flags = 0;
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ int i;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n");
+ if (func) {
+ pm_flags = sdio_get_host_pm_caps(func);
+ PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func),
+ pm_flags);
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR, "sdio_func is not specified\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ handle = cardp->handle;
+
+ if (handle->is_suspended == MFALSE) {
+ PRINTM(MWARN, "Device already resumed\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ handle->is_suspended = MFALSE;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_attach(handle->priv[i]->netdev);
+
+ /* Disable Host Sleep */
+ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT);
+ PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+#endif /* SDIO_SUSPEND_RESUME */
+
+/**
+ * @brief This function writes data into card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ sdio_writeb(((struct sdio_mmc_card *) handle->card)->func, (t_u8) data, reg,
+ (int *) &ret);
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 val;
+
+ val =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, reg,
+ (int *) &ret);
+ *data = val;
+
+ return ret;
+}
+
+/**
+ * @brief This function writes multiple bytes into card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt =
+ (blkmode ==
+ BLOCK_MODE) ? (pmbuf->data_len /
+ MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53w = 1;
+#endif
+ if (!sdio_writesb
+ (((struct sdio_mmc_card *) handle->card)->func, ioport, buffer,
+ blkcnt * blksz))
+ ret = MLAN_STATUS_SUCCESS;
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53w = 2;
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function reads multiple bytes from card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt =
+ (blkmode ==
+ BLOCK_MODE) ? (pmbuf->data_len /
+ MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53r = 1;
+#endif
+ if (!sdio_readsb
+ (((struct sdio_mmc_card *) handle->card)->func, buffer, ioport,
+ blkcnt * blksz))
+ ret = MLAN_STATUS_SUCCESS;
+ else
+ woal_dump_sdio_reg(handle);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53r = 2;
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function registers the IF module in bus driver
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* SDIO Driver Registration */
+ if (sdio_register_driver(&wlan_sdio)) {
+ PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function de-registers the IF module in bus driver
+ *
+ * @return N/A
+ */
+void
+woal_bus_unregister(void)
+{
+ ENTER();
+
+ /* SDIO Driver Unregistration */
+ sdio_unregister_driver(&wlan_sdio);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function de-registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return N/A
+ */
+void
+woal_unregister_dev(moal_handle * handle)
+{
+ ENTER();
+ if (handle->card) {
+ /* Release the SDIO IRQ */
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_release_irq(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_disable_func(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ sdio_set_drvdata(((struct sdio_mmc_card *) handle->card)->func, NULL);
+
+ PRINTM(MWARN, "Making the sdio dev card as NULL\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_dev(moal_handle * handle)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = handle->card;
+ struct sdio_func *func;
+
+ ENTER();
+
+ func = card->func;
+ sdio_claim_host(func);
+ /* Request the SDIO IRQ */
+ ret = sdio_claim_irq(func, woal_sdio_interrupt);
+ if (ret) {
+ PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+ goto release_host;
+ }
+
+ /* Set block size */
+ ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
+ if (ret) {
+ PRINTM(MERROR, "sdio_set_block_seize(): cannot set SDIO block size\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto release_irq;
+ }
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ handle->hotplug_device = &func->dev;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+
+ release_irq:
+ sdio_release_irq(func);
+ release_host:
+ sdio_release_host(func);
+ handle->card = NULL;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function set bus clock on/off
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param option TRUE--on , FALSE--off
+ * @return MLAN_STATUS_SUCCESS
+ */
+int
+woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option)
+{
+ struct sdio_mmc_card *cardp = (struct sdio_mmc_card *) handle->card;
+ struct mmc_host *host = cardp->func->card->host;
+
+ ENTER();
+ if (option == MTRUE) {
+ /* restore value if non-zero */
+ if (cardp->host_clock)
+ host->ios.clock = cardp->host_clock;
+ } else {
+ /* backup value if non-zero, then clear */
+ if (host->ios.clock)
+ cardp->host_clock = host->ios.clock;
+ host->ios.clock = 0;
+ }
+
+ host->ops->set_ios(host, &host->ios);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates card reg based on the Cmd52 value in dev structure
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param func A pointer to store func variable
+ * @param reg A pointer to store reg variable
+ * @param val A pointer to store val variable
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+woal_sdio_read_write_cmd52(moal_handle * handle, int func, int reg, int val)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) handle->card;
+
+ ENTER();
+ /* Save current func and reg for read */
+ handle->cmd52_func = func;
+ handle->cmd52_reg = reg;
+ sdio_claim_host(card->func);
+ if (val >= 0) {
+ /* Perform actual write only if val is provided */
+ if (func)
+ sdio_writeb(card->func, val, reg, &ret);
+ else
+ sdio_f0_writeb(card->func, val, reg, &ret);
+ if (ret) {
+ PRINTM(MERROR, "Cannot write value (0x%x) to func %d reg 0x%x\n",
+ val, func, reg);
+ } else {
+ PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n", (u8) val,
+ func, reg);
+ handle->cmd52_val = val;
+ }
+ } else {
+ if (func)
+ val = sdio_readb(card->func, reg, &ret);
+ else
+ val = sdio_f0_readb(card->func, reg, &ret);
+ if (ret) {
+ PRINTM(MERROR, "Cannot read value from func %d reg 0x%x\n", func,
+ reg);
+ } else {
+ PRINTM(MMSG, "read value (0x%x) from func %d reg 0x%x\n", (u8) val,
+ func, reg);
+ handle->cmd52_val = val;
+ }
+ }
+ sdio_release_host(card->func);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.c b/drivers/net/wireless/sd8797/mlinux/moal_shim.c
new file mode 100644
index 000000000000..25cfdc549f3d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.c
@@ -0,0 +1,1527 @@
+/** @file moal_shim.c
+ *
+ * @brief This file contains the callback functions registered to MLAN
+ *
+ * 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/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#ifdef STA_CFG80211
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** moal_lock */
+typedef struct _moal_lock
+{
+ /** Lock */
+ spinlock_t lock;
+ /** Flags */
+ unsigned long flags;
+} moal_lock;
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Alloc a buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size The size of the buffer to be allocated
+ * @param flag The type of the buffer to be allocated
+ * @param ppbuf Pointer to a buffer location to store buffer pointer allocated
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_malloc(IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ t_u32 mem_flag = GFP_ATOMIC; /* Default type: GFP_ATOMIC */
+
+ if (flag & MLAN_MEM_DMA)
+ mem_flag |= GFP_DMA;
+
+ if (!(*ppbuf = kmalloc(size, mem_flag))) {
+ PRINTM(MERROR, "%s: allocate buffer %d failed!\n", __FUNCTION__,
+ (int) size);
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->malloc_count++;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free a buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pbuf Pointer to the buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+
+ if (!pbuf)
+ return MLAN_STATUS_FAILURE;
+ kfree(pbuf);
+ handle->malloc_count--;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Fill memory with constant byte
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmem Pointer to the memory area
+ * @param byte A constant byte
+ * @param num Number of bytes to fill
+ *
+ * @return Pointer to the memory area
+ */
+t_void *
+moal_memset(IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num)
+{
+ t_void *p = pmem;
+
+ if (pmem && num)
+ p = memset(pmem, byte, num);
+
+ return p;
+}
+
+/**
+ * @brief Copy memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *
+moal_memcpy(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memcpy(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Move memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *
+moal_memmove(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memmove(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Compare two memory areas
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmem1 Pointer to the first memory
+ * @param pmem2 Pointer to the second memory
+ * @param num Number of bytes to compare
+ *
+ * @return Compare result returns by memcmp
+ */
+t_s32
+moal_memcmp(IN t_void * pmoal_handle,
+ IN const t_void * pmem1, IN const t_void * pmem2, IN t_u32 num)
+{
+ t_s32 result;
+
+ result = memcmp(pmem1, pmem2, num);
+
+ return result;
+}
+
+/**
+ * @brief Delay function
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param delay delay in micro-second
+ *
+ * @return N/A
+ */
+t_void
+moal_udelay(IN t_void * pmoal_handle, IN t_u32 delay)
+{
+ if (delay >= 1000)
+ mdelay(delay / 1000);
+ if (delay % 1000)
+ udelay(delay % 1000);
+}
+
+/**
+ * @brief Retrieves the current system time
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param psec Pointer to buf for the seconds of system time
+ * @param pusec Pointer to buf the micro seconds of system time
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_get_system_time(IN t_void * pmoal_handle,
+ OUT t_u32 * psec, OUT t_u32 * pusec)
+{
+ struct timeval t;
+
+ do_gettimeofday(&t);
+ *psec = (t_u32) t.tv_sec;
+ *pusec = (t_u32) t.tv_usec;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pptimer Pointer to the timer
+ * @param callback Pointer to callback function
+ * @param pcontext Pointer to context
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_init_timer(IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext), IN t_void * pcontext)
+{
+ moal_drv_timer *timer = NULL;
+
+ if (!
+ (timer =
+ (moal_drv_timer *) kmalloc(sizeof(moal_drv_timer), GFP_KERNEL)))
+ return MLAN_STATUS_FAILURE;
+ woal_initialize_timer(timer, callback, pcontext);
+ *pptimer = (t_void *) timer;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer)
+{
+ moal_drv_timer *timer = (moal_drv_timer *) ptimer;
+
+ if (timer) {
+ if ((timer->timer_is_canceled == MFALSE) && timer->time_period) {
+ PRINTM(MWARN, "mlan try to free timer without stop timer!\n");
+ woal_cancel_timer(timer);
+ }
+ kfree(timer);
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Start the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ * @param periodic Periodic timer
+ * @param msec Timer value in milliseconds
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_start_timer(IN t_void * pmoal_handle,
+ IN t_void * ptimer, IN t_u8 periodic, IN t_u32 msec)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+
+ ((moal_drv_timer *) ptimer)->timer_is_periodic = periodic;
+ woal_mod_timer((moal_drv_timer *) ptimer, msec);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Stop the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+ woal_cancel_timer((moal_drv_timer *) ptimer);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pplock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_lock *mlock = NULL;
+
+ if (!(mlock = (moal_lock *) kmalloc(sizeof(moal_lock), GFP_ATOMIC)))
+ return MLAN_STATUS_FAILURE;
+ spin_lock_init(&mlock->lock);
+ *pplock = (t_void *) mlock;
+
+ handle->lock_count++;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Lock
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_lock *mlock = plock;
+
+ if (mlock) {
+ kfree(mlock);
+ handle->lock_count--;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Request a spin lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock)
+{
+ moal_lock *mlock = plock;
+ unsigned long flags = 0;
+
+ if (mlock) {
+ spin_lock_irqsave(&mlock->lock, flags);
+ mlock->flags = flags;
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief Request a spin_unlock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock)
+{
+ moal_lock *mlock = (moal_lock *) plock;
+
+ if (mlock) {
+ spin_unlock_irqrestore(&mlock->lock, mlock->flags);
+
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief This function reads one block of firmware data from MOAL
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param offset Offset from where the data will be copied
+ * @param len Length to be copied
+ * @param pbuf Buffer where the data will be copied
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_get_fw_data(IN t_void * pmoal_handle,
+ IN t_u32 offset, IN t_u32 len, OUT t_u8 * pbuf)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+
+ if (!pbuf || !len)
+ return MLAN_STATUS_FAILURE;
+
+ if (offset + len > handle->firmware->size)
+ return MLAN_STATUS_FAILURE;
+
+ memcpy(pbuf, handle->firmware->data + offset, len);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN completes the initialization firmware.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_init_fw request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_init_fw_complete(IN t_void * pmoal_handle, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ if (status == MLAN_STATUS_SUCCESS)
+ handle->hardware_status = HardwareStatusReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN shutdown firmware is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_shutdown request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_shutdown_fw_complete(IN t_void * pmoal_handle, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ handle->hardware_status = HardwareStatusNotReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when an MLAN IOCTL is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pioctl_req pointer to structure mlan_ioctl_req
+ * @param status The status code for mlan_ioctl request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_ioctl_complete(IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_private *priv = NULL;
+ wait_queue *wait;
+ ENTER();
+
+ if (!atomic_read(&handle->ioctl_pending))
+ PRINTM(MERROR, "ERR: Unexpected IOCTL completed: %p\n", pioctl_req);
+ else
+ atomic_dec(&handle->ioctl_pending);
+ priv = woal_bss_index_to_priv(handle, pioctl_req->bss_index);
+
+ wait = (wait_queue *) pioctl_req->reserved_1;
+ PRINTM(MIOCTL,
+ "IOCTL completed: %p id=0x%x sub_id=0x%x, action=%d, status=%d, status_code=0x%x\n",
+ pioctl_req, pioctl_req->req_id, (*(t_u32 *) pioctl_req->pbuf),
+ (int) pioctl_req->action, status, pioctl_req->status_code);
+ if (wait) {
+ wait->condition = MTRUE;
+ wait->status = status;
+ if ((status != MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->status_code == MLAN_ERROR_CMD_TIMEOUT)) {
+ PRINTM(MERROR, "IOCTL: command timeout\n");
+ } else {
+ wake_up_interruptible(wait->wait);
+ }
+ } else {
+ if (priv && (status == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_GET))
+ woal_process_ioctl_resp(priv, pioctl_req);
+ if (status != MLAN_STATUS_SUCCESS)
+ PRINTM(MERROR,
+ "IOCTL failed: id=0x%x, action=%d, status_code=0x%x\n",
+ pioctl_req->req_id, (int) pioctl_req->action,
+ pioctl_req->status_code);
+ kfree(pioctl_req);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates mlan_buffer.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size allocation size requested
+ * @param pmbuf pointer to pointer to the allocated buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_alloc_mlan_buffer(IN t_void * pmoal_handle,
+ IN t_u32 size, OUT pmlan_buffer * pmbuf)
+{
+ if (NULL ==
+ (*pmbuf = woal_alloc_mlan_buffer((moal_handle *) pmoal_handle, size)))
+ return MLAN_STATUS_FAILURE;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf pointer to buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_free_mlan_buffer(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf)
+{
+ if (!pmbuf)
+ return MLAN_STATUS_FAILURE;
+ woal_free_mlan_buffer((moal_handle *) pmoal_handle, pmbuf);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN complete send data packet.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param status The status code for mlan_send_packet request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_send_packet_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ struct sk_buff *skb = NULL;
+ int i;
+ ENTER();
+ if (pmbuf && pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ woal_free_mlan_buffer(handle, pmbuf);
+ atomic_dec(&handle->tx_pending);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ if (pmbuf) {
+ priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (priv) {
+ woal_set_trans_start(priv->netdev);
+ if (skb) {
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ } else {
+ priv->stats.tx_errors++;
+ }
+ if (atomic_dec_return(&handle->tx_pending) < LOW_TX_PENDING) {
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)
+ && (handle->priv[i]->media_connected ||
+ priv->is_adhoc_link_sensed)) {
+ woal_wake_queue(handle->priv[i]->netdev);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP)
+ && (handle->priv[i]->media_connected)) {
+ woal_wake_queue(handle->priv[i]->netdev);
+ }
+#endif
+ }
+ }
+ }
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function write a command/data packet to card.
+ * This function blocks the call until it finishes
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for sent
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_write_data_sync(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
+{
+ return woal_write_data_sync((moal_handle *) pmoal_handle, pmbuf, port,
+ timeout);
+}
+
+/**
+ * @brief This function read data packet/event/command from card.
+ * This function blocks the call until it finish
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for read
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_read_data_sync(IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
+{
+ return woal_read_data_sync((moal_handle *) pmoal_handle, pmbuf, port,
+ timeout);
+}
+
+/**
+ * @brief This function writes data into card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_write_reg(IN t_void * pmoal_handle, IN t_u32 reg, IN t_u32 data)
+{
+ return woal_write_reg((moal_handle *) pmoal_handle, reg, data);
+}
+
+/**
+ * @brief This function reads data from card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_read_reg(IN t_void * pmoal_handle, IN t_u32 reg, OUT t_u32 * data)
+{
+ return woal_read_reg((moal_handle *) pmoal_handle, reg, data);
+}
+
+/**
+ * @brief This function uploads the packet to the network stack
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ struct sk_buff *skb = NULL;
+ ENTER();
+ if (pmbuf) {
+ priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (priv) {
+ if (skb) {
+ skb_reserve(skb, pmbuf->data_offset);
+ skb_put(skb, pmbuf->data_len);
+ pmbuf->pdesc = NULL;
+ pmbuf->pbuf = NULL;
+ pmbuf->data_offset = pmbuf->data_len = 0;
+ } else {
+ PRINTM(MERROR, "%s without skb attach!!!\n", __FUNCTION__);
+ if (!(skb = dev_alloc_skb(pmbuf->data_len + MLAN_NET_IP_ALIGN))) {
+ PRINTM(MERROR, "%s fail to alloc skb\n", __FUNCTION__);
+ status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+ goto done;
+ }
+ skb_reserve(skb, MLAN_NET_IP_ALIGN);
+ memcpy(skb->data, (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset),
+ pmbuf->data_len);
+ skb_put(skb, pmbuf->data_len);
+ }
+ skb->dev = priv->netdev;
+ skb->protocol = eth_type_trans(skb, priv->netdev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (priv->enable_tcp_ack_enh == MTRUE) {
+ woal_check_tcp_fin(priv, skb);
+ }
+
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+ }
+ }
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function handles event receive
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmevent Pointer to the mlan event structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
+{
+ moal_private *priv = NULL;
+#if defined(STA_WEXT) || defined(UAP_SUPPORT)
+ moal_private *pmpriv = NULL;
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#if defined(STA_SUPPORT) || defined(UAP_WEXT)
+#if defined(UAP_SUPPORT) || defined(STA_WEXT)
+ union iwreq_data wrqu;
+#endif
+#endif
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ mlan_ds_ps_info pm_info;
+#endif
+ ENTER();
+
+ PRINTM(MEVENT, "event id:0x%x\n", pmevent->event_id);
+ priv = woal_bss_index_to_priv(pmoal_handle, pmevent->bss_index);
+ if (priv == NULL) {
+ PRINTM(MERROR, "%s: priv is null\n", __FUNCTION__);
+ goto done;
+ }
+ switch (pmevent->event_id) {
+#ifdef STA_SUPPORT
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED:
+ priv->is_adhoc_link_sensed = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_LOST:
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ priv->is_adhoc_link_sensed = MFALSE;
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_LOST);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_CONNECTED:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext) && pmevent->event_len == ETH_ALEN) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, pmevent->event_buf, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext))
+ memcpy(priv->cfg_bssid, pmevent->event_buf, ETH_ALEN);
+#endif
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ break;
+
+ case MLAN_EVENT_ID_DRV_SCAN_REPORT:
+ PRINTM(MINFO, "Scan report\n");
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ priv->phandle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&priv->phandle->async_sem);
+ }
+
+ if (priv->report_scan_result) {
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ woal_inform_bss_from_scan_result(priv, NULL);
+ PRINTM(MINFO, "Reporting scan results\n");
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, MFALSE);
+ priv->scan_request = NULL;
+ }
+ }
+#endif /* STA_CFG80211 */
+
+ priv->report_scan_result = MFALSE;
+ }
+ break;
+
+ case MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_OBSS_SCAN_PARAM,
+ strlen(CUS_EVT_OBSS_SCAN_PARAM));
+ pmevent->event_buf[strlen(CUS_EVT_OBSS_SCAN_PARAM)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BW_CHANGED:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_BW_CHANGED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_BW_CHANGED,
+ strlen(CUS_EVT_BW_CHANGED));
+ pmevent->event_buf[strlen(CUS_EVT_BW_CHANGED)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_BW_CHANGED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif
+ break;
+
+ case MLAN_EVENT_ID_FW_DISCONNECTED:
+ woal_send_disconnect_to_system(priv);
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (!priv->cfg_disconnect &&
+ priv->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+ PRINTM(MINFO, "Successfully disconnected from %pM:"
+ " Reason code %d\n", priv->cfg_bssid,
+ WLAN_REASON_DEAUTH_LEAVING);
+ /* This function must be called only when disconnect issued by
+ the FW, i.e. disconnected by AP. For IBSS mode this call is
+ not valid */
+ cfg80211_disconnected(priv->netdev,
+ WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
+ GFP_KERNEL);
+ }
+ priv->cfg_disconnect = 0;
+ }
+#endif /* STA_CFG80211 */
+ /* Reset wireless stats signal info */
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.qual.noise = 0;
+ }
+#endif
+
+#ifdef REASSOCIATION
+ if (priv->reassoc_on == MTRUE) {
+ PRINTM(MINFO, "Reassoc: trigger the timer\n");
+ priv->reassoc_required = MTRUE;
+ priv->phandle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->reassoc_timer,
+ REASSOC_TIMER_DEFAULT);
+ } else {
+ priv->rate_index = AUTO_RATE;
+ }
+#endif /* REASSOCIATION */
+ break;
+
+ case MLAN_EVENT_ID_FW_MIC_ERR_UNI:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_UNI);
+#else
+ woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI);
+#endif
+ }
+#endif /* STA_WEXT */
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+ NL80211_KEYTYPE_PAIRWISE, -1, NULL,
+ GFP_KERNEL);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_MIC_ERR_MUL:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_MUL);
+#else
+ woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_MUL);
+#endif
+ }
+#endif /* STA_WEXT */
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+ NL80211_KEYTYPE_GROUP, -1, NULL,
+ GFP_KERNEL);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ GFP_KERNEL);
+ priv->rssi_status = MLAN_EVENT_ID_FW_BCN_RSSI_LOW;
+#endif
+ woal_set_rssi_threshold(priv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (!priv->mrvl_rssi_low) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ GFP_KERNEL);
+#endif
+ woal_set_rssi_threshold(priv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH);
+ }
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_MAX_FAIL:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_LINK_QUALITY:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_LINK_QUALITY);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_PORT_RELEASE:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_PORT_RELEASE);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_PRE_BCN_LOST:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST);
+#endif
+#ifdef STA_CFG80211
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ struct cfg80211_bss *bss = NULL;
+ bss =
+ cfg80211_get_bss(priv->wdev->wiphy, NULL, priv->cfg_bssid, NULL,
+ 0, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ if (bss)
+ cfg80211_unlink_bss(priv->wdev->wiphy, bss);
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ GFP_KERNEL);
+ priv->rssi_status = MLAN_EVENT_ID_FW_PRE_BCN_LOST;
+ }
+#endif
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_REPORT_STRING:
+ PRINTM(MINFO, "Report string %s\n", pmevent->event_buf);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, pmevent->event_buf);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_WEP_ICV_ERR:
+ DBG_HEXDUMP(MCMD_D, "WEP ICV error", pmevent->event_buf,
+ pmevent->event_len);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_WEP_ICV_ERR);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_DEFER_HANDLING:
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_EVENT_ID_DRV_DBG_DUMP:
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ break;
+ case MLAN_EVENT_ID_FW_BG_SCAN:
+ if (priv->media_connected == MTRUE)
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MTRUE;
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ woal_inform_bss_from_scan_result(priv, NULL);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ if (priv->mrvl_rssi_low) {
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ GFP_KERNEL);
+ }
+#endif
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_CHANNEL_SWITCH_ANN);
+#endif
+ break;
+#endif /* STA_SUPPORT */
+ case MLAN_EVENT_ID_FW_STOP_TX:
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_START_TX:
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_HS_WAKEUP:
+ /* simulate HSCFG_CANCEL command */
+ woal_cancel_hs(priv, MOAL_NO_WAIT);
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle
+ *)
+ pmoal_handle,
+ MLAN_BSS_ROLE_STA)))
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_WAKEUP);
+#endif /* STA_SUPPORT */
+#endif /* STA_WEXT */
+#ifdef UAP_SUPPORT
+ if ((pmpriv =
+ woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) {
+ pmevent->event_id = UAP_EVENT_ID_HS_WAKEUP;
+ woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif /* UAP_SUPPORT */
+ break;
+ case MLAN_EVENT_ID_DRV_HS_ACTIVATED:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle
+ *)
+ pmoal_handle,
+ MLAN_BSS_ROLE_STA)))
+ {
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_ACTIVATED);
+ }
+#endif /* STA_SUPPORT */
+#endif /* STA_WEXT */
+#if defined(UAP_SUPPORT)
+ if ((pmpriv =
+ woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) {
+ pmevent->event_id = UAP_EVENT_ID_DRV_HS_ACTIVATED;
+ woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ if (priv->phandle->suspend_fail == MFALSE) {
+ woal_get_pm_info(priv, &pm_info);
+ if (pm_info.is_suspend_allowed == MTRUE) {
+ priv->phandle->hs_activated = MTRUE;
+#ifdef MMC_PM_FUNC_SUSPENDED
+ woal_wlan_is_suspended(priv->phandle);
+#endif
+ }
+ priv->phandle->hs_activate_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->hs_activate_wait_q);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_DRV_HS_DEACTIVATED:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle
+ *)
+ pmoal_handle,
+ MLAN_BSS_ROLE_STA)))
+ {
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_DEACTIVATED);
+ }
+#endif
+#endif
+#if defined(UAP_SUPPORT)
+ if ((pmpriv =
+ woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) {
+ pmevent->event_id = UAP_EVENT_ID_DRV_HS_DEACTIVATED;
+ woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ priv->phandle->hs_activated = MFALSE;
+#endif
+ break;
+#ifdef UAP_SUPPORT
+ case MLAN_EVENT_ID_UAP_FW_BSS_START:
+ priv->bss_started = MTRUE;
+ memcpy(priv->current_addr, pmevent->event_buf + 6, ETH_ALEN);
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE:
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_UAP_FW_BSS_IDLE:
+ priv->media_connected = MFALSE;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ case MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED:
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ PRINTM(MEVENT, "FW_REMAIN_ON_CH0ANNEL_EXPIRED cookie = %#llx\n",
+ priv->phandle->cookie);
+ priv->phandle->remain_on_channel = MFALSE;
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ }
+ break;
+#endif
+#endif
+ case MLAN_EVENT_ID_UAP_FW_STA_CONNECT:
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ struct station_info sinfo;
+ t_u8 addr[ETH_ALEN];
+
+ sinfo.filled = 0;
+ sinfo.generation = 0;
+ /* copy the station mac address */
+ memset(addr, 0xFF, ETH_ALEN);
+ memcpy(addr, pmevent->event_buf, ETH_ALEN);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ if (pmevent->event_len > ETH_ALEN) {
+ /* set station info filled flag */
+ sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
+ /* get the assoc request ies and length */
+ sinfo.assoc_req_ies =
+ (const t_u8 *) (pmevent->event_buf + ETH_ALEN);
+ sinfo.assoc_req_ies_len = pmevent->event_len - ETH_ALEN;
+
+ }
+#endif /* KERNEL_VERSION */
+ if (priv->netdev)
+ cfg80211_new_sta(priv->netdev,
+ (t_u8 *) addr, &sinfo, GFP_KERNEL);
+ }
+#endif /* UAP_CFG80211 */
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_STA_CONNECTED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_STA_CONNECTED,
+ strlen(CUS_EVT_STA_CONNECTED));
+ pmevent->event_buf[strlen(CUS_EVT_STA_CONNECTED)] = 0;
+ wrqu.data.pointer = pmevent->event_buf;
+ if ((pmevent->event_len + strlen(CUS_EVT_STA_CONNECTED) + 1) >
+ IW_CUSTOM_MAX)
+ wrqu.data.length = ETH_ALEN + strlen(CUS_EVT_STA_CONNECTED) + 1;
+ else
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_STA_CONNECTED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif /* UAP_WEXT */
+ break;
+ case MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT:
+#ifdef UAP_CFG80211
+ if (IS_UAP_CFG80211(cfg80211_wext)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ /* skip 2 bytes extra header will get the mac address */
+ cfg80211_del_sta(priv->netdev, pmevent->event_buf + 2, GFP_KERNEL);
+#endif /* KERNEL_VERSION */
+ }
+#endif /* UAP_CFG80211 */
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_STA_DISCONNECTED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_STA_DISCONNECTED,
+ strlen(CUS_EVT_STA_DISCONNECTED));
+ pmevent->event_buf[strlen(CUS_EVT_STA_DISCONNECTED)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_STA_DISCONNECTED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif /* UAP_WEXT */
+ break;
+ case MLAN_EVENT_ID_DRV_MGMT_FRAME:
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ }
+#endif /* UAP_WEXT */
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->netdev && priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes) {
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
+#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
+ t_u8 *pkt;
+ pkt = ((t_u8 *) pmevent->event_buf + sizeof(pmevent->event_id));
+
+ /* move addr4 */
+ memmove(pkt + PACKET_ADDR4_POS,
+ pkt + PACKET_ADDR4_POS + ETH_ALEN,
+ pmevent->event_len - sizeof(pmevent->event_id)
+ - PACKET_ADDR4_POS - ETH_ALEN);
+ cfg80211_rx_mgmt(priv->netdev, priv->phandle->chan.center_freq,
+ ((const t_u8 *) pmevent->event_buf)
+ + sizeof(pmevent->event_id),
+ pmevent->event_len - sizeof(pmevent->event_id)
+ - MLAN_MAC_ADDR_LENGTH, GFP_ATOMIC);
+ }
+#endif /* KERNEL_VERSION */
+ }
+#endif /* STA_CFG80211 || UAP_CFG80211 */
+#endif /* WIFI_DIRECT_SUPPORT */
+ break;
+#endif /* UAP_SUPPORT */
+ case MLAN_EVENT_ID_DRV_PASSTHRU:
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_DRV_MEAS_REPORT:
+ /* We have received measurement report, wakeup measurement wait queue */
+ PRINTM(MINFO, "Measurement Report\n");
+ /* Going out of CAC checking period */
+ if (priv->phandle->cac_period == MTRUE) {
+ priv->phandle->cac_period = MFALSE;
+ if (priv->phandle->meas_wait_q_woken == MFALSE) {
+ priv->phandle->meas_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->meas_wait_q);
+ }
+
+ /* Execute delayed BSS START command */
+ if (priv->phandle->delay_bss_start == MTRUE) {
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ /* Clear flag */
+ priv->phandle->delay_bss_start = MFALSE;
+
+ PRINTM(MMSG, "Now CAC measure period end. "
+ "Execute delayed BSS Start command.\n");
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->sub_command = MLAN_OID_BSS_START;
+ memcpy(&bss->param.ssid_bssid,
+ &priv->phandle->delay_ssid_bssid,
+ sizeof(mlan_ssid_bssid));
+
+ if (woal_request_ioctl(priv, req, MOAL_NO_WAIT)
+ != MLAN_STATUS_PENDING) {
+ PRINTM(MMSG, "Delayed BSS Start operation failed!\n");
+ kfree(req);
+ }
+
+ PRINTM(MMSG, "BSS START Complete!\n");
+ }
+ }
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prints the debug message in mlan
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param level debug level
+ * @param pformat point to string format buf
+ *
+ * @return N/A
+ */
+t_void
+moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat, IN ...)
+{
+#ifdef DEBUG_LEVEL1
+ va_list args;
+
+ if (level & MHEX_DUMP) {
+ t_u8 *buf = NULL;
+ int len = 0;
+
+ va_start(args, pformat);
+ buf = (t_u8 *) va_arg(args, t_u8 *);
+ len = (int) va_arg(args, int);
+ va_end(args);
+
+#ifdef DEBUG_LEVEL2
+ if (level & MINFO)
+ HEXDUMP((char *) pformat, buf, len);
+ else
+#endif /* DEBUG_LEVEL2 */
+ {
+ if (level & MERROR)
+ DBG_HEXDUMP(MERROR, (char *) pformat, buf, len);
+ if (level & MCMD_D)
+ DBG_HEXDUMP(MCMD_D, (char *) pformat, buf, len);
+ if (level & MDAT_D)
+ DBG_HEXDUMP(MDAT_D, (char *) pformat, buf, len);
+ if (level & MIF_D)
+ DBG_HEXDUMP(MIF_D, (char *) pformat, buf, len);
+ if (level & MFW_D)
+ DBG_HEXDUMP(MFW_D, (char *) pformat, buf, len);
+ if (level & MEVT_D)
+ DBG_HEXDUMP(MEVT_D, (char *) pformat, buf, len);
+ }
+ } else {
+ va_start(args, pformat);
+ vprintk(pformat, args);
+ va_end(args);
+ }
+#endif /* DEBUG_LEVEL1 */
+}
+
+/**
+ * @brief This function prints the network interface name
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param bss_index BSS index
+ * @param level debug level
+ *
+ * @return N/A
+ */
+t_void
+moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index, IN t_u32 level)
+{
+#ifdef DEBUG_LEVEL1
+ moal_handle *phandle = (moal_handle *) pmoal_handle;
+
+ if (phandle && (drvdbg & level)) {
+ if ((bss_index < MLAN_MAX_BSS_NUM) && phandle->priv[bss_index] &&
+ phandle->priv[bss_index]->netdev)
+ printk("%s: ", phandle->priv[bss_index]->netdev->name);
+ }
+#endif /* DEBUG_LEVEL1 */
+}
+
+/**
+ * @brief This function asserts the existence of the passed argument
+ *
+ * @param pmoal_handle A pointer to moal_private structure
+ * @param cond Condition to check
+ *
+ * @return N/A
+ */
+t_void
+moal_assert(IN t_void * pmoal_handle, IN t_u32 cond)
+{
+ if (!cond)
+ panic("Assert failed: Panic!");
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.h b/drivers/net/wireless/sd8797/mlinux/moal_shim.h
new file mode 100644
index 000000000000..ee50a2105f0f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.h
@@ -0,0 +1,95 @@
+/** @file moal_shim.h
+ *
+ * @brief This file contains declaration referring to
+ * functions defined in moal module
+ *
+ * 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/21/2008: initial version
+************************************************************/
+
+#ifndef _MOAL_H
+#define _MOAL_H
+
+mlan_status moal_get_fw_data(IN t_void * pmoal_handle,
+ IN t_u32 offset, IN t_u32 len, OUT t_u8 * pbuf);
+mlan_status moal_init_fw_complete(IN t_void * pmoal_handle,
+ IN mlan_status status);
+mlan_status moal_shutdown_fw_complete(IN t_void * pmoal_handle,
+ IN mlan_status status);
+mlan_status moal_ioctl_complete(IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+mlan_status moal_alloc_mlan_buffer(IN t_void * pmoal_handle, IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+mlan_status moal_free_mlan_buffer(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+mlan_status moal_send_packet_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+/** moal_write_reg */
+mlan_status moal_write_reg(IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+/** moal_read_reg */
+mlan_status moal_read_reg(IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+mlan_status moal_write_data_sync(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+mlan_status moal_read_data_sync(IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+mlan_status moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf);
+mlan_status moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent);
+mlan_status moal_malloc(IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf);
+mlan_status moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf);
+t_void *moal_memset(IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+t_void *moal_memcpy(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num);
+t_void *moal_memmove(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num);
+t_s32 moal_memcmp(IN t_void * pmoal_handle,
+ IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+/** moal_udelay */
+t_void moal_udelay(IN t_void * pmoal_handle, IN t_u32 udelay);
+mlan_status moal_get_system_time(IN t_void * pmoal_handle, OUT t_u32 * psec,
+ OUT t_u32 * pusec);
+mlan_status moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock);
+mlan_status moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock);
+mlan_status moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock);
+mlan_status moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock);
+t_void moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat,
+ IN ...);
+t_void moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index,
+ IN t_u32 level);
+t_void moal_assert(IN t_void * pmoal_handle, IN t_u32 cond);
+mlan_status moal_init_timer(IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+mlan_status moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer);
+mlan_status moal_start_timer(IN t_void * pmoal_handle,
+ IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+mlan_status moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer);
+
+#endif /*_MOAL_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
new file mode 100644
index 000000000000..ed44cdefe43b
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
@@ -0,0 +1,2520 @@
+/** @file moal_sta_cfg80211.c
+ *
+ * @brief This file contains the functions for STA CFG80211.
+ *
+ * Copyright (C) 2011-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.
+ *
+ */
+
+#include "moal_cfg80211.h"
+#include "moal_sta_cfg80211.h"
+static int woal_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request);
+
+static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
+
+static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+
+static int woal_cfg80211_disconnect(struct wiphy *wiphy,
+ struct net_device *dev, t_u16 reason_code);
+
+static int woal_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ t_u8 * mac, struct station_info *sinfo);
+
+static int woal_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ t_u8 * mac, struct station_info *sinfo);
+
+static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled,
+ int timeout);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst);
+#endif
+
+static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS)
+ enum tx_power_setting type,
+#else
+ enum nl80211_tx_power_setting type,
+#endif
+ int dbm);
+
+static int woal_cfg80211_join_ibss(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+
+static int woal_cfg80211_leave_ibss(struct wiphy *wiphy,
+ struct net_device *dev);
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie);
+
+void woal_cfg80211_remain_on_channel_done(void *context);
+
+static int woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type
+ channel_type, unsigned int duration,
+ u64 * cookie);
+
+static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie);
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/** cfg80211 STA operations */
+static struct cfg80211_ops woal_cfg80211_sta_ops = {
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .scan = woal_cfg80211_scan,
+ .connect = woal_cfg80211_connect,
+ .disconnect = woal_cfg80211_disconnect,
+ .get_station = woal_cfg80211_get_station,
+ .dump_station = woal_cfg80211_dump_station,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+ .set_channel = woal_cfg80211_set_channel,
+ .join_ibss = woal_cfg80211_join_ibss,
+ .leave_ibss = woal_cfg80211_leave_ibss,
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .set_default_key = woal_cfg80211_set_default_key,
+ .set_power_mgmt = woal_cfg80211_set_power_mgmt,
+ .set_tx_power = woal_cfg80211_set_tx_power,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ .set_cqm_rssi_config = woal_cfg80211_set_cqm_rssi_config,
+#endif
+};
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/** cfg80211 Wifi Direct operations */
+static struct cfg80211_ops woal_cfg80211_wifi_direct_ops = {
+ .add_virtual_intf = woal_cfg80211_add_virtual_intf,
+ .del_virtual_intf = woal_cfg80211_del_virtual_intf,
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .scan = woal_cfg80211_scan,
+ .connect = woal_cfg80211_connect,
+ .disconnect = woal_cfg80211_disconnect,
+ .get_station = woal_cfg80211_get_station,
+ .dump_station = woal_cfg80211_dump_station,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+ .set_channel = woal_cfg80211_set_channel,
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .add_beacon = woal_cfg80211_add_beacon,
+ .set_beacon = woal_cfg80211_set_beacon,
+ .del_beacon = woal_cfg80211_del_beacon,
+ .mgmt_frame_register = woal_cfg80211_mgmt_frame_register,
+ .mgmt_tx = woal_cfg80211_mgmt_tx,
+ .mgmt_tx_cancel_wait = woal_cfg80211_mgmt_tx_cancel_wait,
+ .remain_on_channel = woal_cfg80211_remain_on_channel,
+ .cancel_remain_on_channel = woal_cfg80211_cancel_remain_on_channel,
+ .set_default_key = woal_cfg80211_set_default_key,
+ .set_power_mgmt = woal_cfg80211_set_power_mgmt,
+ .set_tx_power = woal_cfg80211_set_tx_power,
+};
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/********************************************************
+ Local Variables
+********************************************************/
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+static const struct ieee80211_txrx_stypes
+ ieee80211_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ // BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
+ 0,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_MESH_POINT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+
+};
+#endif
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Get the encryption mode from cipher
+ *
+ * @param cipher Cipher cuite
+ * @param wpa_enabled WPA enable or disable
+ *
+ * @return MLAN_ENCRYPTION_MODE_*
+ */
+static int
+woal_cfg80211_get_encryption_mode(t_u32 cipher, int *wpa_enabled)
+{
+ int encrypt_mode;
+
+ ENTER();
+
+ *wpa_enabled = 0;
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ *wpa_enabled = 1;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ *wpa_enabled = 1;
+ break;
+ default:
+ encrypt_mode = -1;
+ }
+
+ LEAVE();
+ return encrypt_mode;
+}
+
+/**
+ * @brief Check the pairwise or group cipher for
+ * WEP enabled or not
+ *
+ * @param cipher MLAN Cipher cuite
+ *
+ * @return 1 -- enable or 0 -- disable
+ */
+static int
+woal_cfg80211_is_alg_wep(t_u32 cipher)
+{
+ int alg = 0;
+ ENTER();
+
+ if (cipher == MLAN_ENCRYPTION_MODE_WEP40 ||
+ cipher == MLAN_ENCRYPTION_MODE_WEP104)
+ alg = 1;
+
+ LEAVE();
+ return alg;
+}
+
+/**
+ * @brief Convert NL802.11 channel type into driver channel type
+ *
+ * The mapping is as follows -
+ * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL
+ * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL
+ * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE
+ * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW
+ * Others -> NO_SEC_CHANNEL
+ *
+ * @param channel_type Channel type
+ *
+ * @return Driver channel type
+ */
+static int
+woal_cfg80211_channel_type_to_channel(enum nl80211_channel_type channel_type)
+{
+ int channel;
+
+ ENTER();
+
+ switch (channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ channel = NO_SEC_CHANNEL;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ channel = SEC_CHANNEL_ABOVE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ channel = SEC_CHANNEL_BELOW;
+ break;
+ default:
+ channel = NO_SEC_CHANNEL;
+ }
+ LEAVE();
+ return channel;
+}
+
+/**
+ * @brief Convert secondary channel type to NL80211 channel type
+ *
+ * The mapping is as follows -
+ * NO_SEC_CHANNEL -> NL80211_CHAN_HT20
+ * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS
+ * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS
+ * Others -> NL80211_CHAN_HT20
+ *
+ * @param channel_type Driver channel type
+ *
+ * @return nl80211_channel_type type
+ */
+static enum nl80211_channel_type
+woal_channel_to_nl80211_channel_type(int channel_type)
+{
+ enum nl80211_channel_type channel;
+
+ ENTER();
+
+ switch (channel_type) {
+ case NO_SEC_CHANNEL:
+ channel = NL80211_CHAN_HT20;
+ break;
+ case SEC_CHANNEL_ABOVE:
+ channel = NL80211_CHAN_HT40PLUS;
+ break;
+ case SEC_CHANNEL_BELOW:
+ channel = NL80211_CHAN_HT40MINUS;
+ break;
+ default:
+ channel = NL80211_CHAN_HT20;
+ }
+ LEAVE();
+ return channel;
+}
+
+/**
+ * @brief Convert driver band configuration to IEEE band type
+ *
+ * @param band Driver band configuration
+ *
+ * @return IEEE band type
+ */
+t_u8
+woal_band_cfg_to_ieee_band(t_u32 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ ret_radio_type = IEEE80211_BAND_5GHZ;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ case BAND_GN:
+ case BAND_B | BAND_GN:
+ default:
+ ret_radio_type = IEEE80211_BAND_2GHZ;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
+
+/**
+ * @brief Convert NL80211 interface type to MLAN_BSS_MODE_*
+ *
+ * @param iftype Interface type of NL80211
+ *
+ * @return Driver bss mode
+ */
+static t_u32
+woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)
+{
+ switch (iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return MLAN_BSS_MODE_IBSS;
+ case NL80211_IFTYPE_STATION:
+ return MLAN_BSS_MODE_INFRA;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ return MLAN_BSS_MODE_AUTO;
+ }
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param enable enable/disable flag
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wps_cfg(moal_private * priv, int enable)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (enable)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure ASSOC IE
+ *
+ * @param priv A pointer to moal private structure
+ * @param ie A pointer to ie data
+ * @param ie_len The length of ie data
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_assoc_ies_cfg(moal_private * priv, t_u8 * ie, int ie_len)
+{
+ int bytes_left = ie_len;
+ t_u8 *pcurrent_ptr = ie;
+ int total_ie_len;
+ t_u8 element_len;
+ int ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case RSN_IE:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr,
+ &total_ie_len)) {
+ PRINTM(MERROR, "Fail to set RSN IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set RSN IE\n");
+ break;
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui, sizeof(wps_oui))) {
+ PRINTM(MIOCTL, "Enable WPS session\n");
+ woal_wps_cfg(priv, MTRUE);
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr,
+ &total_ie_len)) {
+ PRINTM(MERROR, "Fail to Set VENDOR SPECIFIC IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set VENDOR SPECIFIC IE, OUI: %02x:%02x:%02x:%02x\n",
+ pvendor_ie->vend_hdr.oui[0], pvendor_ie->vend_hdr.oui[1],
+ pvendor_ie->vend_hdr.oui[2], pvendor_ie->vend_hdr.oui_type);
+ break;
+ default:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr,
+ &total_ie_len)) {
+ PRINTM(MERROR, "Fail to set GEN IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set GEN IE\n");
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+ done:
+ return ret;
+}
+
+/**
+ * @brief Send domain info command to FW
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_send_domain_info_cmd_fw(moal_private * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband = NULL;
+ struct ieee80211_channel *channel = NULL;
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = 0;
+ mlan_ds_11d_cfg *cfg_11d = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (!priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "No wdev or wiphy in priv\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ band = woal_band_cfg_to_ieee_band(radio_cfg->param.band_cfg.config_bands);
+ if (!priv->wdev->wiphy->bands[band]) {
+ PRINTM(MERROR, "11D: setting domain info in FW failed");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ kfree(req);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Set country code */
+ cfg_11d->param.domain_info.country_code[0] = priv->country_code[0];
+ cfg_11d->param.domain_info.country_code[1] = priv->country_code[1];
+ cfg_11d->param.domain_info.country_code[2] = ' ';
+ cfg_11d->param.domain_info.band = band;
+
+ sband = priv->wdev->wiphy->bands[band];
+ for (i = 0; (i < sband->n_channels) &&
+ (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D); i++) {
+ channel = &sband->channels[i];
+ if (channel->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ next_chan = first_chan = (t_u32) channel->hw_value;
+ max_pwr = channel->max_power;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (channel->hw_value == next_chan + 1 && channel->max_power == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .first_chan = first_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .no_of_chan = no_of_parsed_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ next_chan = first_chan = (t_u32) channel->hw_value;
+ max_pwr = channel->max_power;
+ no_of_parsed_chan = 1;
+ }
+ }
+
+ if (flag) {
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .first_chan = first_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .no_of_chan = no_of_parsed_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ }
+ cfg_11d->param.domain_info.no_of_sub_band = no_of_sub_band;
+
+ /* Send domain info command to FW */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "11D: Error setting domain info in FW\n");
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the channel and
+ * change domain info according to that channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_set_rf_channel(moal_private * priv,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ int ret = 0;
+ t_u32 mode, config_bands = 0;
+ mlan_ioctl_req *req1 = NULL, *req2 = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ ENTER();
+
+ mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
+
+ req1 = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req1 == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ radio_cfg = (mlan_ds_radio_cfg *) req1->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req1->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (chan) {
+ req1->action = MLAN_ACT_SET;
+ /* Set appropriate bands */
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ config_bands = BAND_B | BAND_G | BAND_GN;
+ else
+ config_bands = BAND_AN | BAND_A;
+ if (mode == MLAN_BSS_MODE_IBSS)
+ radio_cfg->param.band_cfg.adhoc_start_band = config_bands;
+ radio_cfg->param.band_cfg.config_bands = config_bands;
+ /* Set channel offset */
+ radio_cfg->param.band_cfg.sec_chan_offset =
+ woal_cfg80211_channel_type_to_channel(channel_type);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req1, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_send_domain_info_cmd_fw(priv);
+ }
+
+ PRINTM(MINFO, "Setting band %d, channel bandwidth %d and mode = %d\n",
+ config_bands, radio_cfg->param.band_cfg.sec_chan_offset, mode);
+
+ if (!chan)
+ goto done;
+
+ req2 = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req2 == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req2->pbuf;
+
+ bss->param.bss_chan.freq = chan->center_freq;
+ /* Convert frequency to channel */
+ bss->param.bss_chan.channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req2->req_id = MLAN_IOCTL_BSS;
+ req2->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req2, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(priv, bss->param.bss_chan.channel)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req1)
+ kfree(req1);
+ if (req2)
+ kfree(req2);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_ewpa_mode(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Try Get All */
+ memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase));
+ memcpy(&sec->param.passphrase.ssid, &ssid_bssid->ssid,
+ sizeof(sec->param.passphrase.ssid));
+ memcpy(&sec->param.passphrase.bssid, &ssid_bssid->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option))
+ goto error;
+ sec->param.ewpa_enabled = MFALSE;
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ if (sec->param.passphrase.psk.passphrase.passphrase_len > 0) {
+ sec->param.ewpa_enabled = MTRUE;
+ }
+ } else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK)
+ sec->param.ewpa_enabled = MTRUE;
+
+ sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ error:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encryption mode and enable WPA
+ *
+ * @param priv A pointer to moal_private structure
+ * @param encrypt_mode Encryption mode
+ * @param wpa_enabled WPA enable or not
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_set_auth(moal_private * priv, int encrypt_mode, int wpa_enabled)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+
+ if (wpa_enabled) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, 1))
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Informs the CFG802.11 subsystem of a new BSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new BSS connection. If we do not register the new BSS,
+ * a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct ieee80211_channel *chan;
+ mlan_scan_resp scan_resp;
+ BSSDescriptor_t *scan_table;
+ t_u64 ts = 0;
+ u16 cap_info = 0;
+ int i = 0;
+ struct cfg80211_bss *pub = NULL;
+ ENTER();
+ if (!priv->wdev || !priv->wdev->wiphy) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
+ MOAL_IOCTL_WAIT,
+ &scan_resp)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (scan_resp.num_in_scan_table) {
+ scan_table = (BSSDescriptor_t *) scan_resp.pscan_table;
+ for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ if (ssid) {
+ /* Inform specific BSS only */
+ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, ssid->ssid_len))
+ continue;
+ }
+ if (!scan_table[i].freq) {
+ PRINTM(MERROR, "Invalid channel number %d\n",
+ (int) scan_table[i].channel);
+ continue;
+ }
+ chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq);
+ if (!chan) {
+ PRINTM(MERROR,
+ "Fail to get chan with freq: channel=%d freq=%d\n",
+ (int) scan_table[i].channel, (int) scan_table[i].freq);
+ continue;
+ }
+ memcpy(&ts, scan_table[i].time_stamp, sizeof(ts));
+ memcpy(&cap_info, &scan_table[i].cap_info, sizeof(cap_info));
+ pub = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ scan_table[i].mac_address,
+ ts, cap_info,
+ scan_table[i].beacon_period,
+ scan_table[i].pbeacon_buf +
+ WLAN_802_11_FIXED_IE_SIZE,
+ scan_table[i].beacon_buf_size -
+ WLAN_802_11_FIXED_IE_SIZE,
+ -RSSI_DBM_TO_MDM(scan_table[i].rssi),
+ GFP_KERNEL);
+ if (pub) {
+ pub->len_information_elements = pub->len_beacon_ies;
+ cfg80211_put_bss(pub);
+ }
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Informs the CFG802.11 subsystem of a new IBSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new IBSS connection. If we do not register the
+ * new IBSS, a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param cahn A pointer to ieee80211_channel structure
+ * @param beacon_interval Beacon interval
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_cfg80211_inform_ibss_bss(moal_private * priv,
+ struct ieee80211_channel *chan,
+ t_u16 beacon_interval)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)];
+ int ie_len = 0;
+ struct cfg80211_bss *bss = NULL;
+
+ ENTER();
+
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret)
+ goto done;
+
+ memset(ie_buf, 0, sizeof(ie_buf));
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = bss_info.ssid.ssid_len;
+
+ memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)],
+ &bss_info.ssid.ssid, bss_info.ssid.ssid_len);
+ ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
+ beacon_interval, ie_buf, ie_len,
+ signal.bcn_rssi_avg, GFP_KERNEL);
+ if (bss)
+ cfg80211_put_bss(bss);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver for (re)association
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sme A pointer to connect parameters
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_assoc(moal_private * priv, void *sme)
+{
+ struct cfg80211_ibss_params *ibss_param = NULL;
+ struct cfg80211_connect_params *conn_param = NULL;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ t_u32 auth_type = 0, mode;
+ int wpa_enabled = 0;
+ int group_enc_mode = 0, pairwise_enc_mode = 0;
+ int alg_is_wep = 0;
+
+ t_u8 *ssid, ssid_len = 0, *bssid;
+ t_u8 *ie = NULL;
+ int ie_len = 0;
+ struct ieee80211_channel *channel = NULL;
+ t_u16 beacon_interval = 0;
+ bool privacy;
+
+ ENTER();
+
+ mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
+
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ ibss_param = (struct cfg80211_ibss_params *) sme;
+ ssid = ibss_param->ssid;
+ ssid_len = ibss_param->ssid_len;
+ bssid = ibss_param->bssid;
+ channel = ibss_param->channel;
+ if (ibss_param->ie_len)
+ ie = ibss_param->ie;
+ ie_len = ibss_param->ie_len;
+ beacon_interval = ibss_param->beacon_interval;
+ privacy = ibss_param->privacy;
+ } else {
+ conn_param = (struct cfg80211_connect_params *) sme;
+ ssid = conn_param->ssid;
+ ssid_len = conn_param->ssid_len;
+ bssid = conn_param->bssid;
+ channel = conn_param->channel;
+ if (conn_param->ie_len)
+ ie = conn_param->ie;
+ ie_len = conn_param->ie_len;
+ privacy = conn_param->privacy;
+ }
+
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ req_ssid.ssid_len = ssid_len;
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(req_ssid.ssid, ssid, ssid_len);
+ if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (channel) {
+ /* Get the secondary channel offset */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(priv,
+ channel,
+ woal_channel_to_nl80211_channel_type
+ (radio_cfg->param.
+ band_cfg.
+ sec_chan_offset))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_ewpa_mode(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
+ KEY_INDEX_CLEAR_ALL, NULL, 1)) {
+ /* Disable keys and clear all previous security settings */
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ie && ie_len) { /* Set the IE */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_assoc_ies_cfg(priv, ie, ie_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (conn_param && mode != MLAN_BSS_MODE_IBSS) {
+ /* These parameters are only for managed mode */
+ if (conn_param->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+ auth_type = MLAN_AUTH_MODE_OPEN;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ auth_type = MLAN_AUTH_MODE_SHARED;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_NETWORK_EAP)
+ auth_type = MLAN_AUTH_MODE_NETWORKEAP;
+ else
+ auth_type = MLAN_AUTH_MODE_AUTO;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_type)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (conn_param->crypto.n_ciphers_pairwise) {
+ pairwise_enc_mode =
+ woal_cfg80211_get_encryption_mode(conn_param->
+ crypto.ciphers_pairwise[0],
+ &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode, wpa_enabled);
+ if (ret)
+ goto done;
+ }
+
+ if (conn_param->crypto.cipher_group) {
+ group_enc_mode =
+ woal_cfg80211_get_encryption_mode(conn_param->
+ crypto.cipher_group,
+ &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, group_enc_mode, wpa_enabled);
+ if (ret)
+ goto done;
+ }
+
+ if (conn_param->key) {
+ alg_is_wep =
+ woal_cfg80211_is_alg_wep(pairwise_enc_mode) |
+ woal_cfg80211_is_alg_wep(group_enc_mode);
+ if (alg_is_wep) {
+ PRINTM(MINFO, "Setting wep encryption with "
+ "key len %d\n", conn_param->key_len);
+ /* Set the WEP key */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, conn_param->key,
+ conn_param->key_len,
+ conn_param->key_idx)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Enable the WEP key by key index */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, NULL, 0,
+ conn_param->key_idx)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ mlan_ds_bss *bss = NULL;
+ /* Change beacon interval */
+ if ((beacon_interval < MLAN_MIN_BEACON_INTERVAL) ||
+ (beacon_interval > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (req)
+ kfree(req);
+ req = NULL;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ bss->param.bcn_interval = beacon_interval;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* "privacy" is set only for ad-hoc mode */
+ if (privacy) {
+ /*
+ * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that
+ * the firmware can find a matching network from the
+ * scan. cfg80211 does not give us the encryption
+ * mode at this stage so just setting it to wep here
+ */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT,
+ MLAN_AUTH_MODE_OPEN)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wpa_enabled = 0;
+ ret = woal_cfg80211_set_auth(priv,
+ MLAN_ENCRYPTION_MODE_WEP104,
+ wpa_enabled);
+ if (ret)
+ goto done;
+ }
+ }
+ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
+ if (bssid)
+ memcpy(&ssid_bssid.bssid, bssid, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect before try to associate */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+
+ if (mode != MLAN_BSS_MODE_IBSS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Inform the BSS information to kernel, otherwise kernel will give a
+ panic after successful assoc */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_inform_bss_from_scan_result(priv, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv);
+
+ PRINTM(MINFO, "Trying to associate to %s and bssid %pM\n",
+ (char *) req_ssid.ssid, ssid_bssid.bssid);
+
+ /* Zero SSID implies use BSSID to connect */
+ if (bssid)
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ else /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Inform the IBSS information to kernel, otherwise kernel will give a
+ panic after successful assoc */
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_inform_ibss_bss(priv, channel, beacon_interval)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ret) {
+ /* clear IE */
+ ie_len = 0;
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, NULL, &ie_len);
+ }
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+/**
+ * @brief Set/Get DTIM period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value DTIM period
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_set_get_dtim_period(moal_private * priv,
+ t_u32 action, t_u8 wait_option, t_u8 * value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_DTIM_PERIOD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ mib->param.dtim_period = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = (t_u8) mib->param.dtim_period;
+ }
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static mlan_status
+woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_signal signal;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ mlan_bss_info bss_info;
+ t_u8 dtim_period = 0;
+#endif
+
+ ENTER();
+ sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
+ STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ sinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
+ if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40) {
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ }
+ if (rate->param.data_rate.tx_ht_gi == MLAN_HT_SGI) {
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ }
+ sinfo->txrate.mcs = rate->param.data_rate.tx_data_rate;
+ sinfo->rx_bytes = priv->stats.rx_bytes;
+ sinfo->tx_bytes = priv->stats.tx_bytes;
+ sinfo->rx_packets = priv->stats.rx_packets;
+ sinfo->tx_packets = priv->stats.tx_packets;
+ sinfo->signal = signal.bcn_rssi_avg;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ /* Update BSS information */
+ sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->bss_param.flags = 0;
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret)
+ goto done;
+ if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+ sinfo->bss_param.beacon_interval = bss_info.beacon_interval;
+ /* Get DTIM period */
+ ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT, &dtim_period);
+ if (ret) {
+ PRINTM(MERROR, "Get DTIM period failed\n");
+ goto done;
+ }
+ sinfo->bss_param.dtim_period = dtim_period;
+#endif
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Request the driver to change regulatory domain
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param request A pointer to regulatory_request structure
+ *
+ * @return 0
+ */
+static int
+woal_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __FUNCTION__);
+ LEAVE();
+ return -EINVAL;
+ }
+
+ PRINTM(MINFO, "cfg80211 regulatory domain callback "
+ "%c%c\n", request->alpha2[0], request->alpha2[1]);
+
+ if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, request->alpha2))
+ PRINTM(MERROR, "Set country code failed!\n");
+ memcpy(priv->country_code, request->alpha2, COUNTRY_CODE_LEN);
+
+ switch (request->initiator) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ PRINTM(MINFO, "Regulatory domain BY_DRIVER\n");
+ break;
+ case NL80211_REGDOM_SET_BY_CORE:
+ PRINTM(MINFO, "Regulatory domain BY_CORE\n");
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ PRINTM(MINFO, "Regulatory domain BY_USER\n");
+ break;
+ /* TODO: apply driver specific changes in channel flags based on the
+ request initiator if necessory. * */
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ PRINTM(MINFO, "Regulatory domain BY_COUNTRY_IE\n");
+ break;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(priv))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to do a scan. Always returning
+ * zero meaning that the scan request is given to driver,
+ * and will be valid until passed to cfg80211_scan_done().
+ * To inform scan results, call cfg80211_inform_bss().
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param request A pointer to cfg80211_scan_request structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ wlan_user_scan_cfg scan_req;
+ struct ieee80211_channel *chan;
+ int ret = 0, i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Received scan request on %s\n", dev->name);
+
+ if (priv->scan_request && priv->scan_request != request) {
+ LEAVE();
+ return -EBUSY;
+ }
+ priv->scan_request = request;
+
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ for (i = 0; i < priv->scan_request->n_ssids; i++) {
+ memcpy(scan_req.ssid_list[i].ssid,
+ priv->scan_request->ssids[i].ssid,
+ priv->scan_request->ssids[i].ssid_len);
+ if (priv->scan_request->ssids[i].ssid_len)
+ scan_req.ssid_list[i].max_len = 0;
+ else
+ scan_req.ssid_list[i].max_len = 0xff;
+ PRINTM(MIOCTL, "scan: ssid=%s\n", scan_req.ssid_list[i].ssid);
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ priv->scan_request->n_ssids) {
+ if (!memcmp(scan_req.ssid_list[i - 1].ssid, "DIRECT-", 7)) {
+ /* Enable wildcard ssid scan */
+ memcpy(scan_req.ssid_list[i].ssid, "DIRECT-*", 8);
+ scan_req.ssid_list[i].max_len = 0xff;
+ }
+ }
+#endif
+#endif
+ for (i = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+ scan_req.chan_list[i].chan_number = chan->hw_value;
+ scan_req.chan_list[i].radio_type = chan->band;
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ else
+ scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ scan_req.chan_list[i].scan_time = 0;
+ }
+ if (priv->scan_request->ie && priv->scan_request->ie_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0,
+ NULL, 0, NULL, 0,
+ (t_u8 *) priv->scan_request->ie,
+ priv->scan_request->ie_len,
+ MGMT_MASK_PROBE_REQ)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /** Clear SCAN IE in Firmware */
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ);
+ }
+ if (MLAN_STATUS_SUCCESS != woal_do_scan(priv, &scan_req)) {
+ ret = -EAGAIN;
+ }
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to connect to the ESS with
+ * the specified parameters from kernel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param sme A pointer to cfg80211_connect_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "Received association request on %s\n", dev->name);
+
+ if (priv->wdev->iftype != NL80211_IFTYPE_STATION
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+ ) {
+ PRINTM(MERROR, "Received infra assoc request "
+ "when station not in infra mode\n");
+ LEAVE();
+ return -EINVAL;
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+ && (priv->wdev->iftype == NL80211_IFTYPE_STATION
+ || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ /* if bsstype == wifi direct, and iftype == station or p2p client, that
+ means wpa_supplicant wants to enable wifi direct functionality, so
+ we should init p2p client. Note that due to kernel iftype check,
+ ICS wpa_supplicant could not updaet iftype to init p2p client, so
+ we have to done it here. */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) {
+ PRINTM(MERROR, "Init p2p client for wpa_supplicant failed.\n");
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+ }
+ }
+#endif
+#endif
+
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ ret = woal_cfg80211_assoc(priv, (void *) sme);
+
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+
+ if (!ret) {
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
+ NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL);
+ PRINTM(MINFO, "Associated to bssid %pM successfully\n",
+ priv->cfg_bssid);
+ } else {
+ PRINTM(MINFO, "Association to bssid %pM failed\n", priv->cfg_bssid);
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
+ NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to disconnect
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param reason_code Reason code
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ t_u16 reason_code)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+
+ ENTER();
+ PRINTM(MINFO, "Received disassociation request on %s\n", dev->name);
+
+ if (priv->cfg_disconnect) {
+ PRINTM(MERROR, "Disassociation already in progress\n");
+ LEAVE();
+ return -EBUSY;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ priv->cfg_disconnect = 1;
+
+ if (woal_disconnect(priv, MOAL_IOCTL_WAIT, priv->cfg_bssid) !=
+ MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Successfully disconnected from %pM: Reason code %d\n",
+ priv->cfg_bssid, reason_code);
+
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to get the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ t_u8 * mac, struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+
+ ENTER();
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return woal_uap_cfg80211_get_station(wiphy, dev, mac, sinfo);
+ }
+#endif
+#endif
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+ if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) {
+ PRINTM(MINFO, "cfg80211: Request not for this station!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) {
+ PRINTM(MERROR, "cfg80211: Failed to get station info\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param idx Station index
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ t_u8 * mac, struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ if (!priv->media_connected || idx != 0) {
+ PRINTM(MINFO, "cfg80211: Media not connected or"
+ " not for this station!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ memcpy(mac, priv->cfg_bssid, ETH_ALEN);
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) {
+ PRINTM(MERROR, "cfg80211: Failed to get station info\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to Join the specified
+ * IBSS (or create if necessary)
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to cfg80211_ibss_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+ PRINTM(MERROR, "Request IBSS join received "
+ "when station not in ibss mode\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ ret = woal_cfg80211_assoc(priv, (void *) params);
+
+ if (!ret) {
+ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
+ PRINTM(MINFO, "Joined/created adhoc network with bssid"
+ " %pM successfully\n", priv->cfg_bssid);
+ } else {
+ PRINTM(MINFO, "Failed creating/joining adhoc network\n");
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to leave the IBSS
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ if (priv->cfg_disconnect) {
+ PRINTM(MERROR, "IBSS leave already in progress\n");
+ LEAVE();
+ return -EBUSY;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ priv->cfg_disconnect = 1;
+
+ PRINTM(MINFO, "Leaving from IBSS %pM\n", priv->cfg_bssid);
+ if (woal_disconnect(priv, MOAL_IOCTL_WAIT, priv->cfg_bssid) !=
+ MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to change the IEEE power save
+ * mdoe
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param enabled Enable or disable
+ * @param timeout Timeout value
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled, int timeout)
+{
+ int ret = 0, disabled;
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ if (enabled)
+ disabled = 0;
+ else
+ disabled = 1;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, timeout)) {
+ ret = -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the transmit power
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param type TX power adjustment type
+ * @param dbm TX power in dbm
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_set_tx_power(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS)
+ enum tx_power_setting type,
+#else
+ enum nl80211_tx_power_setting type,
+#endif
+ int dbm)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ mlan_power_cfg_t power_cfg;
+
+ ENTER();
+
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __FUNCTION__);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (type) {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = dbm;
+ } else
+ power_cfg.is_power_auto = 1;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+/**
+ * CFG802.11 operation handler for connection quality monitoring.
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param rssi_thold rssi threshold
+ * @param rssi_hyst rssi hysteresis
+ */
+static int
+woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ ENTER();
+ priv->cqm_rssi_thold = rssi_thold;
+ priv->cqm_rssi_hyst = rssi_hyst;
+
+ PRINTM(MIOCTL, "rssi_thold=%d rssi_hyst=%d\n",
+ (int) rssi_thold, (int) rssi_hyst);
+ woal_set_rssi_threshold(priv, 0);
+ LEAVE();
+ return 0;
+}
+#endif
+
+/**
+ * @brief Sets up the CFG802.11 specific HT capability fields
+ * with default values
+ *
+ * @param ht_info A pointer to ieee80211_sta_ht_cap structure
+ * @param dev_cap Device capability informations
+ * @param mcs_set Device MCS sets
+ *
+ * @return N/A
+ */
+static void
+woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
+ t_u32 dev_cap, t_u8 * mcs_set)
+{
+ ENTER();
+
+ ht_info->ht_supported = true;
+ ht_info->ampdu_factor = 0x3;
+ ht_info->ampdu_density = 0x6;
+
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ ht_info->cap = 0;
+ if (mcs_set)
+ memcpy(ht_info->mcs.rx_mask, mcs_set, sizeof(ht_info->mcs.rx_mask));
+ if (dev_cap & MBIT(8)) /* 40Mhz intolarance enabled */
+ ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT;
+ if (dev_cap & MBIT(17)) /* Channel width 20/40Mhz support */
+ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if ((dev_cap >> 20) & 0x03) /* Delayed ACK supported */
+ ht_info->cap |= IEEE80211_HT_CAP_DELAY_BA;
+ if (dev_cap & MBIT(22)) /* Rx LDPC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+ if (dev_cap & MBIT(23)) /* Short GI @ 20Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ if (dev_cap & MBIT(24)) /* Short GI @ 40Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+ if (dev_cap & MBIT(25)) /* Tx STBC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+ if (dev_cap & MBIT(26)) /* Rx STBC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_RX_STBC;
+ if (dev_cap & MBIT(27)) /* MIMO PS supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
+ if (dev_cap & MBIT(29)) /* Green field supported */
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (dev_cap & MBIT(31)) /* MAX AMSDU supported */
+ ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ LEAVE();
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/**
+ * @brief remain on channel config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param cancel cancel remain on channel flag
+ * @param status A pointer to status, success, in process or reject
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type channel_type,
+ * @param duration Duration wait to receive frame
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_remain_on_channel_cfg(moal_private * priv,
+ t_u8 wait_option, t_u8 remove,
+ t_u8 * status,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ t_u32 duration)
+{
+ mlan_ds_remain_chan chan_cfg;
+ int ret = 0;
+
+ ENTER();
+ memset(&chan_cfg, 0, sizeof(mlan_ds_remain_chan));
+ if (remove) {
+ chan_cfg.remove = MTRUE;
+ } else {
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ chan_cfg.bandcfg = 0;
+ else if (chan->band == IEEE80211_BAND_5GHZ)
+ chan_cfg.bandcfg = 1;
+ switch (channel_type) {
+ case NL80211_CHAN_HT40MINUS:
+ chan_cfg.bandcfg |= SEC_CHANNEL_BELOW;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_cfg.bandcfg |= SEC_CHANNEL_ABOVE;
+ break;
+
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ default:
+ break;
+ }
+ chan_cfg.channel = ieee80211_frequency_to_channel(chan->center_freq);
+ chan_cfg.remain_period = duration;
+ }
+ if (MLAN_STATUS_SUCCESS ==
+ woal_set_remain_channel_ioctl(priv, wait_option, &chan_cfg))
+ *status = chan_cfg.status;
+ else
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg(priv,
+ MOAL_IOCTL_WAIT, MTRUE, &status,
+ NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Make chip remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type
+ * @param duration Duration for timer
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration, u64 * cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+
+ if (!chan || !cookie) {
+ PRINTM(MERROR, "Invalid parameter for remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /** cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg(priv,
+ MOAL_IOCTL_WAIT, MTRUE, &status,
+ NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->cookie = 0;
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
+ MFALSE, &status, chan, channel_type,
+ (t_u32) duration)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (status == 0) {
+ /* remain on channel operation success */
+ /* we need update the value cookie */
+ *cookie = (u64) random32() | 1;
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->cookie = *cookie;
+ priv->phandle->channel_type = channel_type;
+ memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel));
+ cfg80211_ready_on_channel(dev, *cookie, chan,
+ channel_type, duration, GFP_KERNEL);
+ PRINTM(MIOCTL, "Set remain on Channel: channel=%d cookie = %#llx\n",
+ ieee80211_frequency_to_channel(chan->center_freq),
+ priv->phandle->cookie);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+ PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie);
+ if (woal_cfg80211_remain_on_channel_cfg(priv,
+ MOAL_IOCTL_WAIT, MTRUE, &status,
+ NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->phandle->remain_on_channel = MFALSE;
+ if (priv->phandle->cookie)
+ priv->phandle->cookie = 0;
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/**
+ * @brief Initialize the wiphy
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cfg80211_sta_init_wiphy(moal_private * priv, t_u8 wait_option)
+{
+ int retry_count, rts_thr, frag_thr, disabled;
+ struct wiphy *wiphy = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ t_u32 hw_dev_cap;
+
+ ENTER();
+
+ if (priv->wdev)
+ wiphy = priv->wdev->wiphy;
+ else {
+ PRINTM(MERROR, "Invalid parameter when init wiphy.\n");
+ goto done;
+ }
+
+ /* Get 11n tx parameters from MLAN */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ hw_dev_cap = cfg_11n->param.htcap_cfg.htcap;
+
+ /* Get supported MCS sets */
+ memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg));
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize parameters for 2GHz and 5GHz bands */
+ woal_cfg80211_setup_sta_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
+ hw_dev_cap,
+ cfg_11n->param.supported_mcs_set);
+ /* For 2.4G band only card, this shouldn't be set
+ woal_cfg80211_setup_sta_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap,
+ hw_dev_cap, cfg_11n->param.supported_mcs_set); */
+ if (req)
+ kfree(req);
+
+ /* Set retry limit count to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_GET, wait_option, &retry_count)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ wiphy->retry_long = (t_u8) retry_count;
+ wiphy->retry_short = (t_u8) retry_count;
+ wiphy->max_scan_ie_len = MAX_IE_SIZE;
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /* we should add mgmt_stypes for both STA & Wifi Direct, while only
+ initialize duration_timer for Wifi Direct */
+ wiphy->mgmt_stypes = ieee80211_mgmt_stypes;
+ wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION;
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ /* Set RTS threshold to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_GET, wait_option, &rts_thr)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (rts_thr < MLAN_RTS_MIN_VALUE || rts_thr > MLAN_RTS_MAX_VALUE)
+ rts_thr = MLAN_FRAG_RTS_DISABLED;
+ wiphy->rts_threshold = (t_u32) rts_thr;
+
+ /* Set fragment threshold to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_GET, wait_option, &frag_thr)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (frag_thr < MLAN_RTS_MIN_VALUE || frag_thr > MLAN_RTS_MAX_VALUE)
+ frag_thr = MLAN_FRAG_RTS_DISABLED;
+ wiphy->frag_threshold = (t_u32) frag_thr;
+
+ /* Get IEEE power save mode */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
+ MLAN_ACT_GET, &disabled,
+ 0)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Save the IEEE power save mode to wiphy, because after warmreset wiphy
+ power save should be updated instead of using the last saved
+ configuration */
+ if (disabled)
+ priv->wdev->ps = MFALSE;
+ else
+ priv->wdev->ps = MTRUE;
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Register the device with cfg80211
+ *
+ * @param dev A pointer to net_device structure
+ * @param bss_type BSS type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_sta_cfg80211(struct net_device * dev, t_u8 bss_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ void *wdev_priv = NULL;
+ struct wireless_dev *wdev = NULL;
+ mlan_fw_info fw_info;
+
+ ENTER();
+
+ /* Allocate wireless device */
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ PRINTM(MERROR, "Could not allocate wireless device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ if (bss_type == MLAN_BSS_TYPE_STA)
+ /* Allocate wiphy */
+ wdev->wiphy = wiphy_new(&woal_cfg80211_sta_ops, sizeof(moal_private *));
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ /* Allocate wiphy */
+ wdev->wiphy =
+ wiphy_new(&woal_cfg80211_wifi_direct_ops, sizeof(moal_private *));
+#endif
+#endif
+ else {
+ PRINTM(MERROR, "Unexpected bss_type when register cfg80211\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ if (!wdev->wiphy) {
+ PRINTM(MERROR, "Could not allocate wiphy device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+ if (bss_type == MLAN_BSS_TYPE_STA) {
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ wdev->wiphy->interface_modes =
+ MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_ADHOC);
+ wdev->wiphy->max_scan_ssids = 10;
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ wdev->wiphy->interface_modes = MBIT(NL80211_IFTYPE_STATION) |
+ MBIT(NL80211_IFTYPE_P2P_GO) |
+ MBIT(NL80211_IFTYPE_P2P_CLIENT) |
+ MBIT(NL80211_IFTYPE_ADHOC) | MBIT(NL80211_IFTYPE_AP) |
+ MBIT(NL80211_IFTYPE_MONITOR);
+ wdev->wiphy->max_scan_ssids = 10;
+ }
+#endif
+#endif
+
+ /* Set phy name like net device name */
+ dev_set_name(&wdev->wiphy->dev, dev->name);
+
+ /* Make this wiphy known to this driver only */
+ wdev->wiphy->privid = mrvl_wiphy_privid;
+
+ /* Supported bands */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ if (MLAN_STATUS_SUCCESS ==
+ woal_request_get_fw_info(priv, MOAL_CMD_WAIT, &fw_info)) {
+ if (fw_info.fw_bands & BAND_A)
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+ }
+ /* Initialize cipher suits */
+ wdev->wiphy->cipher_suites = cfg80211_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
+
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* We are using custom domains */
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+
+ wdev->wiphy->reg_notifier = woal_cfg80211_reg_notifier;
+
+ /* Set moal_private pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wdev->wiphy);
+
+ *(unsigned long *) wdev_priv = (unsigned long) priv;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) || defined(COMPAT_WIRELESS)
+ set_wiphy_dev(wdev->wiphy, (struct device *) priv->phandle->hotplug_device);
+#endif
+
+ if (wiphy_register(wdev->wiphy) < 0) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ } else {
+ PRINTM(MINFO, "Successfully registered wiphy device\n");
+ LEAVE();
+ return ret;
+ }
+
+ wiphy_unregister(wdev->wiphy);
+ err_wdev:
+ dev->ieee80211_ptr = NULL;
+ if (wdev && wdev->wiphy)
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h
new file mode 100644
index 000000000000..a83957c5c031
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h
@@ -0,0 +1,41 @@
+/** @file moal_sta_cfg80211.h
+ *
+ * @brief This file contains the STA CFG80211 specific defines.
+ *
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef _MOAL_STA_CFG80211_H_
+#define _MOAL_STA_CFG80211_H_
+
+/** Convert RSSI signal strength from dBm to mBm (100*dBm) */
+#define RSSI_DBM_TO_MDM(x) ((x) * 100)
+
+mlan_status woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type);
+mlan_status woal_cfg80211_sta_init_wiphy(moal_private * priv, t_u8 wait_option);
+
+mlan_status
+woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep,
+ t_u32 cipher, const t_u8 * key, int key_len,
+ const t_u8 * seq, int seq_len, t_u8 key_index,
+ const t_u8 * addr, int disable);
+
+mlan_status
+woal_cfg80211_set_wep_keys(moal_private * priv, const t_u8 * key, int key_len,
+ t_u8 index);
+
+#endif /* _MOAL_STA_CFG80211_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.c b/drivers/net/wireless/sd8797/mlinux/moal_uap.c
new file mode 100644
index 000000000000..fb8e2a7d6571
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.c
@@ -0,0 +1,2692 @@
+/** @file moal_uap.c
+ *
+ * @brief This file contains the major functions in UAP
+ * driver.
+ *
+ * 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 "moal_main.h"
+#include "moal_uap.h"
+#include "moal_sdio.h"
+#include "moal_eth_ioctl.h"
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief uap addba parameter handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_addba_param(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_param param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_addba_param() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d txamsdu=%d rxamsdu=%d\n",
+ (int) param.action, (int) param.timeout, (int) param.txwinsize,
+ (int) param.rxwinsize, (int) param.txamsdu, (int) param.rxamsdu);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba param from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba param in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg_11n->param.addba_param.timeout = param.timeout;
+ cfg_11n->param.addba_param.txwinsize = param.txwinsize;
+ cfg_11n->param.addba_param.rxwinsize = param.rxwinsize;
+ cfg_11n->param.addba_param.txamsdu = param.txamsdu;
+ cfg_11n->param.addba_param.rxamsdu = param.rxamsdu;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ param.timeout = cfg_11n->param.addba_param.timeout;
+ param.txwinsize = cfg_11n->param.addba_param.txwinsize;
+ param.rxwinsize = cfg_11n->param.addba_param.rxwinsize;
+ param.txamsdu = cfg_11n->param.addba_param.txamsdu;
+ param.rxamsdu = cfg_11n->param.addba_param.rxamsdu;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap aggr priority tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ aggr_prio_tbl param;
+ int ret = 0;
+ int i = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_aggr_priotbl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "aggr_prio_tbl", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get aggr_prio_tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set aggr_prio_tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.aggr_prio_tbl.ampdu[i] = param.ampdu[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[i] = param.amsdu[i];
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.ampdu[i] = cfg_11n->param.aggr_prio_tbl.ampdu[i];
+ param.amsdu[i] = cfg_11n->param.aggr_prio_tbl.amsdu[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap addba reject tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_addba_reject(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_reject_para param;
+ int ret = 0;
+ int i = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba_reject tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba_reject tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.addba_reject[i] = param.addba_reject[i];
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.addba_reject[i] = cfg_11n->param.addba_reject[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get_fw_info handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ fw_info fw;
+ mlan_fw_info fw_info;
+ int ret = 0;
+
+ ENTER();
+ memset(&fw, 0, sizeof(fw));
+ memset(&fw_info, 0, sizeof(fw_info));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_get_fw_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&fw, req->ifr_data, sizeof(fw))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fw.fw_release_number = fw_info.fw_ver;
+ fw.hw_dev_mcs_support = fw_info.hw_dev_mcs_support;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &fw, sizeof(fw))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure deep sleep
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ deep_sleep_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if (!param.action) {
+ /* Get deep_sleep status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set deep_sleep in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ if (param.deep_sleep == MTRUE) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = param.idle_time;
+ } else {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON)
+ param.deep_sleep = MTRUE;
+ else
+ param.deep_sleep = MFALSE;
+ param.idle_time = pm->param.auto_deep_sleep.idletime;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure tx_pause settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_txdatapause(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ tx_data_pause_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!param.action) {
+ /* Get Tx data pause status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set Tx data pause in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.tx_datapause.tx_pause = param.txpause;
+ misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ param.txpause = misc->param.tx_datapause.tx_pause;
+ param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap sdcmd52rw ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_sdcmd52_rw(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ sdcmd52_para param;
+ t_u8 func, data = 0;
+ int ret = 0, reg;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_sdcmd52_rw() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8) param.cmd52_params[0];
+ reg = (t_u32) param.cmd52_params[1];
+
+ if (!param.action) {
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ data =
+ sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ reg, &ret);
+ else
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)->
+ func, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg);
+ goto done;
+ }
+ param.cmd52_params[2] = data;
+ } else {
+ data = (t_u8) param.cmd52_params[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func,
+ reg, data);
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg);
+ goto done;
+ }
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure snmp mib
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_snmp_mib(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_snmp_mib *snmp = NULL;
+ snmp_mib_para param;
+ t_u8 value[MAX_SNMP_VALUE_SIZE];
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(value, 0, MAX_SNMP_VALUE_SIZE);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_snmp_mib() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para", (t_u8 *) & param, sizeof(param));
+ if (param.action) {
+ if (copy_from_user(value, req->ifr_data + sizeof(param),
+ MIN(param.oid_val_len, MAX_SNMP_VALUE_SIZE))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para value", value,
+ MIN(param.oid_val_len, sizeof(t_u32)));
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ snmp = (mlan_ds_snmp_mib *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
+ switch (param.oid) {
+ case OID_80211D_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D;
+ break;
+ case OID_80211H_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H;
+ break;
+ default:
+ PRINTM(MERROR, "%s: Unsupported SNMP_MIB OID (%d).\n", __FUNCTION__,
+ param.oid);
+ goto done;
+ }
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ snmp->param.oid_value = *(t_u32 *) value;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ if (copy_to_user(req->ifr_data + sizeof(param), &snmp->param.oid_value,
+ MIN(param.oid_val_len, sizeof(t_u32)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure domain info
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_domain_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11d_cfg *cfg11d = NULL;
+ domain_info_para param;
+ t_u8 tlv[MAX_DOMAIN_TLV_LEN];
+ t_u16 tlv_data_len = 0;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(tlv, 0, MAX_DOMAIN_TLV_LEN);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_domain_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para", (t_u8 *) & param, sizeof(param));
+ if (param.action) {
+ /* get tlv header */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param), TLV_HEADER_LEN)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ tlv_data_len = ((t_u16 *) (tlv))[1];
+ if ((TLV_HEADER_LEN + tlv_data_len) > sizeof(tlv)) {
+ PRINTM(MERROR, "TLV buffer is overflowed");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* get full tlv */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param),
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para tlv", tlv,
+ TLV_HEADER_LEN + tlv_data_len);
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11d = (mlan_ds_11d_cfg *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11D_CFG;
+ cfg11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(cfg11d->param.domain_tlv, tlv,
+ MIN(MAX_IE_SIZE, (TLV_HEADER_LEN + tlv_data_len)));
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ tlv_data_len = ((t_u16 *) (cfg11d->param.domain_tlv))[1];
+ if (copy_to_user
+ (req->ifr_data + sizeof(param), &cfg11d->param.domain_tlv,
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(DFS_TESTING_SUPPORT)
+/**
+ * @brief configure dfs testing settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11h_cfg *cfg11h = NULL;
+ dfs_testing_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_dfs_testing() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "dfs_testing_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11h = (mlan_ds_11h_cfg *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
+ cfg11h->sub_command = MLAN_OID_11H_DFS_TESTING;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg11h->param.dfs_testing.usr_cac_period_msec = param.usr_cac_period;
+ cfg11h->param.dfs_testing.usr_nop_period_sec = param.usr_nop_period;
+ cfg11h->param.dfs_testing.usr_no_chan_change = param.no_chan_change;
+ cfg11h->param.dfs_testing.usr_fixed_new_chan = param.fixed_new_chan;
+ priv->phandle->cac_period_jiffies = param.usr_cac_period * HZ / 1000;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!param.action) { /* GET */
+ param.usr_cac_period = cfg11h->param.dfs_testing.usr_cac_period_msec;
+ param.usr_nop_period = cfg11h->param.dfs_testing.usr_nop_period_sec;
+ param.no_chan_change = cfg11h->param.dfs_testing.usr_no_chan_change;
+ param.fixed_new_chan = cfg11h->param.dfs_testing.usr_fixed_new_chan;
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Configure TX beamforming support
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ tx_bf_cfg_para_hdr param;
+ t_u16 action = 0;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(param));
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_tx_bf_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) {
+ /* Get BF configurations */
+ action = MLAN_ACT_GET;
+ } else {
+ /* Set BF configurations */
+ action = MLAN_ACT_SET;
+ }
+ if (copy_from_user(&bf_cfg, req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "bf_cfg", (t_u8 *) & bf_cfg, sizeof(bf_cfg));
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ &bf_cfg, sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap hs_cfg ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req,
+ BOOLEAN invoke_hostcmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_hs_cfg hscfg;
+ ds_hs_cfg hs_cfg;
+ mlan_bss_info bss_info;
+ t_u16 action;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ memset(&hs_cfg, 0, sizeof(ds_hs_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hs_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl hscfg: flags=0x%x condition=0x%x gpio=%d gap=0x%x\n",
+ hs_cfg.flags, hs_cfg.conditions, (int) hs_cfg.gpio, hs_cfg.gap);
+
+ /* HS config is blocked if HS is already activated */
+ if ((hs_cfg.flags & HS_CFG_FLAG_CONDITION) &&
+ (hs_cfg.conditions != HOST_SLEEP_CFG_CANCEL ||
+ invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (hs_cfg.flags & HS_CFG_FLAG_SET) {
+ action = MLAN_ACT_SET;
+ if (hs_cfg.flags != HS_CFG_FLAG_ALL) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg);
+ }
+ if (hs_cfg.flags & HS_CFG_FLAG_CONDITION)
+ hscfg.conditions = hs_cfg.conditions;
+ if (hs_cfg.flags & HS_CFG_FLAG_GPIO)
+ hscfg.gpio = hs_cfg.gpio;
+ if (hs_cfg.flags & HS_CFG_FLAG_GAP)
+ hscfg.gap = hs_cfg.gap;
+
+ if (invoke_hostcmd == MTRUE) {
+ /* Issue IOCTL to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ action = MLAN_ACT_GET;
+ }
+
+ /* Issue IOCTL to invoke hostcmd */
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) {
+ hs_cfg.flags =
+ HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO | HS_CFG_FLAG_GAP;
+ hs_cfg.conditions = hscfg.conditions;
+ hs_cfg.gpio = hscfg.gpio;
+ hs_cfg.gap = hscfg.gap;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (req->ifr_data != NULL) {
+ ret = woal_uap_hs_cfg(dev, req, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap mgmt_frame_control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_mgmt_frame_control(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ t_u16 action = 0;
+ mgmt_frame_ctrl param;
+ mlan_uap_bss_param sys_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_mgmt_frame_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (param.action) {
+ action = MLAN_ACT_SET;
+ } else {
+ action = MLAN_ACT_GET;
+ }
+ if (action == MLAN_ACT_SET) {
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_config);
+ sys_config.mgmt_ie_passthru_mask = param.mask;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, action, MOAL_IOCTL_WAIT, &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ param.mask = sys_config.mgmt_ie_passthru_mask;
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get tx rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0, i = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ tx_rate_cfg_t tx_rate_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_tx_rate_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&tx_rate_config, req->ifr_data, sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) mreq->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ mreq->req_id = MLAN_IOCTL_RATE;
+ if (!(tx_rate_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ if (tx_rate_config.rate == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((tx_rate_config.rate != MLAN_RATE_INDEX_MCS32) &&
+ ((tx_rate_config.rate < 0) ||
+ (tx_rate_config.rate > MLAN_RATE_INDEX_MCS15))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = tx_rate_config.rate;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (tx_rate_config.action) {
+ priv->rate_index = tx_rate_config.action;
+ } else {
+ if (rate->param.rate_cfg.is_rate_auto)
+ tx_rate_config.rate = AUTO_RATE;
+ else
+ tx_rate_config.rate = rate->param.rate_cfg.rate;
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ tx_rate_config.bitmap_rates[i] =
+ rate->param.rate_cfg.bitmap_rates[i];
+ }
+
+ if (copy_to_user(req->ifr_data, &tx_rate_config, sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (mreq)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RF antenna mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ ant_cfg_t antenna_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&antenna_config, 0, sizeof(ant_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&antenna_config, req->ifr_data, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) mreq->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (!(antenna_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode;
+ radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (mreq->action == MLAN_ACT_GET) {
+ antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna;
+ antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna;
+ if (copy_to_user(req->ifr_data, &antenna_config, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (mreq)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ t_u32 subcmd = 0;
+ ENTER();
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&subcmd, req->ifr_data, sizeof(subcmd))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl subcmd=%d\n", (int) subcmd);
+ switch (subcmd) {
+ case UAP_ADDBA_PARA:
+ ret = woal_uap_addba_param(dev, req);
+ break;
+ case UAP_AGGR_PRIOTBL:
+ ret = woal_uap_aggr_priotbl(dev, req);
+ break;
+ case UAP_ADDBA_REJECT:
+ ret = woal_uap_addba_reject(dev, req);
+ break;
+ case UAP_FW_INFO:
+ ret = woal_uap_get_fw_info(dev, req);
+ break;
+ case UAP_DEEP_SLEEP:
+ ret = woal_uap_deep_sleep(dev, req);
+ break;
+ case UAP_TX_DATA_PAUSE:
+ ret = woal_uap_txdatapause(dev, req);
+ break;
+ case UAP_SDCMD52_RW:
+ ret = woal_uap_sdcmd52_rw(dev, req);
+ break;
+ case UAP_SNMP_MIB:
+ ret = woal_uap_snmp_mib(dev, req);
+ break;
+ case UAP_DOMAIN_INFO:
+ ret = woal_uap_domain_info(dev, req);
+ break;
+#ifdef DFS_TESTING_SUPPORT
+ case UAP_DFS_TESTING:
+ ret = woal_uap_dfs_testing(dev, req);
+ break;
+#endif
+ case UAP_TX_BF_CFG:
+ ret = woal_uap_tx_bf_cfg(dev, req);
+ break;
+ case UAP_HS_CFG:
+ ret = woal_uap_hs_cfg(dev, req, MTRUE);
+ break;
+ case UAP_HS_SET_PARA:
+ ret = woal_uap_hs_set_para(dev, req);
+ break;
+ case UAP_MGMT_FRAME_CONTROL:
+ ret = woal_uap_mgmt_frame_control(dev, req);
+ break;
+ case UAP_TX_RATE_CFG:
+ ret = woal_uap_tx_rate_cfg(dev, req);
+ break;
+ case UAP_ANTENNA_CFG:
+ ret = woal_uap_antenna_cfg(dev, req);
+ break;
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap station deauth ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_deauth_param deauth_param;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&deauth_param, 0, sizeof(mlan_deauth_param));
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_sta_deauth_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&deauth_param, req->ifr_data, sizeof(mlan_deauth_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl deauth station: %02x:%02x:%02x:%02x:%02x:%02x, reason=%d\n",
+ deauth_param.mac_addr[0], deauth_param.mac_addr[1],
+ deauth_param.mac_addr[2], deauth_param.mac_addr[3],
+ deauth_param.mac_addr[4], deauth_param.mac_addr[5],
+ deauth_param.reason_code);
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) ioctl_req->pbuf;
+
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&bss->param.deauth_param, &deauth_param, sizeof(mlan_deauth_param));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ int data[2] = { 0, 0 };
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_radio_ctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data[0]) {
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) mreq->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ mreq->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = (t_u32) data[1];
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ if (mreq)
+ kfree(mreq);
+ } else {
+ /* Get radio status */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ data[1] = bss_info.radio_on;
+ if (copy_to_user(req->ifr_data, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap bss control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0, data = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, data);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap power mode ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ds_ps_mgmt ps_mgmt;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
+ "inact_to=%d min_awake=%d max_awake=%d\n", ps_mgmt.flags,
+ (int) ps_mgmt.ps_mode, (int) ps_mgmt.sleep_param.ctrl_bitmap,
+ (int) ps_mgmt.sleep_param.min_sleep,
+ (int) ps_mgmt.sleep_param.max_sleep,
+ (int) ps_mgmt.inact_param.inactivity_to,
+ (int) ps_mgmt.inact_param.min_awake,
+ (int) ps_mgmt.inact_param.max_awake);
+
+ if (ps_mgmt.
+ flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
+ PS_FLAG_INACT_SLEEP_PARAM)) {
+ PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n", ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) {
+ PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n",
+ (int) ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+ if (ps_mgmt.flags) {
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(&pm_cfg->param.ps_mgmt, &ps_mgmt, sizeof(mlan_ds_ps_mgmt));
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+ if (!ps_mgmt.flags) {
+ /* Copy to user */
+ if (copy_to_user
+ (req->ifr_data, &pm_cfg->param.ps_mgmt, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS config ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ int offset = 0;
+ t_u32 action = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_cfg_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get action */
+ if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ offset += sizeof(action);
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ if (action == 1) {
+ ioctl_req->action = MLAN_ACT_SET;
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_SET) {
+ /* Get the BSS config from user */
+ if (copy_from_user
+ (&bss->param.bss_config, req->ifr_data + offset,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ offset = sizeof(action);
+
+ /* Copy to user : BSS config */
+ if (copy_to_user
+ (req->ifr_data + offset, &bss->param.bss_config,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get station list handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_get_sta_list_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_get_sta_list_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *) ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ /* Copy to user : sta_list */
+ if (copy_to_user
+ (req->ifr_data, &info->param.sta_list, sizeof(mlan_ds_sta_list))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uAP set WAPI key ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi_key_ioctl(moal_private * priv, wapi_msg * msg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ wapi_key_msg *key_msg = NULL;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+ if (msg->msg_len != sizeof(wapi_key_msg)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ key_msg = (wapi_key_msg *) msg->msg;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_len = MLAN_MAX_KEY_LENGTH;
+ memcpy(sec->param.encrypt_key.mac_addr, key_msg->mac_addr, ETH_ALEN);
+ sec->param.encrypt_key.key_index = key_msg->key_id;
+ if (0 == memcmp(key_msg->mac_addr, bcast_addr, ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+ memcpy(sec->param.encrypt_key.key_material, key_msg->key,
+ sec->param.encrypt_key.key_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable wapi in firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_enable_wapi(moal_private * priv, t_u8 enable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+
+ /* Change AP default setting */
+ req->action = MLAN_ACT_SET;
+ if (enable == MFALSE) {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_WAPI;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Set AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+ if (enable)
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief uAP set WAPI flag ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi_flag_ioctl(moal_private * priv, wapi_msg * msg)
+{
+ t_u8 wapi_psk_ie[] =
+ { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x02,
+ 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x00
+ };
+ t_u8 wapi_cert_ie[] =
+ { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
+ 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x00
+ };
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+ misc->param.gen_ie.len = sizeof(wapi_psk_ie);
+ if (msg->msg[0] & WAPI_MODE_PSK) {
+ memcpy(misc->param.gen_ie.ie_data, wapi_psk_ie, misc->param.gen_ie.len);
+ } else if (msg->msg[0] & WAPI_MODE_CERT) {
+ memcpy(misc->param.gen_ie.ie_data, wapi_cert_ie,
+ misc->param.gen_ie.len);
+ } else if (msg->msg[0] == 0) {
+ /* disable WAPI in driver */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, 0))
+ ret = -EFAULT;
+ woal_enable_wapi(priv, MFALSE);
+ goto done;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_enable_wapi(priv, MTRUE);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set wapi ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ wapi_msg msg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_set_wapi() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ if (copy_from_user(&msg, req->ifr_data, sizeof(msg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "set wapi msg_type = %d, msg_len=%d\n", msg.msg_type,
+ msg.msg_len);
+ DBG_HEXDUMP(MCMD_D, "wapi msg", msg.msg, MIN(msg.msg_len, sizeof(msg.msg)));
+
+ switch (msg.msg_type) {
+ case P80211_PACKET_WAPIFLAG:
+ ret = woal_uap_set_wapi_flag_ioctl(priv, &msg);
+ break;
+ case P80211_PACKET_SETKEY:
+ ret = woal_uap_set_wapi_key_ioctl(priv, &msg);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Initialize the members of mlan_uap_bss_param
+ * which are uploaded from firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_uap_get_bss_param(moal_private * priv, mlan_uap_bss_param * sys_cfg,
+ t_u8 wait_option)
+{
+ mlan_ds_bss *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_bss *) req->pbuf;
+ info->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get bss info failed!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memcpy(sys_cfg, &info->param.bss_config, sizeof(mlan_uap_bss_param));
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set 11n status based on the configured security mode
+ *
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (action == MLAN_ACT_DISABLE) {
+ if ((sys_cfg->supported_mcs_set[0] == 0)
+ && (sys_cfg->supported_mcs_set[4] == 0)
+ && (sys_cfg->supported_mcs_set[1] == 0)
+ ) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0;
+ sys_cfg->supported_mcs_set[4] = 0;
+ sys_cfg->supported_mcs_set[1] = 0;
+ }
+ }
+
+ if (action == MLAN_ACT_ENABLE) {
+ if ((sys_cfg->supported_mcs_set[0] != 0)
+ || (sys_cfg->supported_mcs_set[4] != 0)
+ || (sys_cfg->supported_mcs_set[1] != 0)
+ ) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0xFF;
+ sys_cfg->supported_mcs_set[4] = 0x01;
+ sys_cfg->supported_mcs_set[1] = 0xFF;
+ }
+ }
+
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Parse AP configuration from ASCII string
+ *
+ * @param ap_cfg A pointer to mlan_uap_bss_param structure
+ * @param buf A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_ap_cfg_parse_data(mlan_uap_bss_param * ap_cfg, t_s8 * buf)
+{
+ int ret = 0, atoi_ret;
+ int set_sec = 0, set_key = 0, set_chan = 0;
+ int set_preamble = 0, set_scb = 0, set_ssid = 0;
+ t_s8 *begin = buf, *value = NULL, *opt = NULL;
+
+ ENTER();
+
+ while (begin) {
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (opt && !strncmp(opt, "END", strlen("END"))) {
+ if (!ap_cfg->ssid.ssid_len) {
+ PRINTM(MERROR, "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Parsing terminated by string END\n");
+ break;
+ }
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "ASCII_CMD", strlen("ASCII_CMD"))) {
+ if (strncmp(value, "AP_CFG", strlen("AP_CFG"))) {
+ PRINTM(MERROR, "ASCII_CMD: %s not matched with AP_CFG\n",
+ value);
+ ret = -EFAULT;
+ goto done;
+ }
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "SSID", strlen("SSID"))) {
+ if (set_ssid) {
+ PRINTM(MWARN, "Skipping SSID, found again!\n");
+ continue;
+ }
+ if (strlen(value) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->ssid.ssid_len = strlen(value);
+ strncpy((char *) ap_cfg->ssid.ssid, value, strlen(value));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", ap_cfg->ssid.ssid,
+ (int) ap_cfg->ssid.ssid_len);
+ set_ssid = 1;
+ } else {
+ PRINTM(MERROR, "AP_CFG: Invalid option %s, "
+ "expect SSID\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (!strncmp(opt, "SEC", strlen("SEC"))) {
+ if (set_sec) {
+ PRINTM(MWARN, "Skipping SEC, found again!\n");
+ continue;
+ }
+ if (!strnicmp(value, "open", strlen("open"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else if (!strnicmp(value, "wpa2-psk", strlen("wpa2-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA2;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ } else if (!strnicmp(value, "wpa-psk", strlen("wpa-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
+ } else if (!strnicmp(value, "wep128", strlen("wep128"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_STATIC_WEP;
+ } else {
+ PRINTM(MERROR, "AP_CFG: Invalid value=%s for %s\n", value, opt);
+ ret = -EFAULT;
+ goto done;
+ }
+ set_sec = 1;
+ } else if (!strncmp(opt, "KEY", strlen("KEY"))) {
+ if (set_key) {
+ PRINTM(MWARN, "Skipping KEY, found again!\n");
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol == PROTOCOL_STATIC_WEP) {
+ if (strlen(value) != MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Invalid WEP KEY length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->wep_cfg.key0.key_index = 0;
+ ap_cfg->wep_cfg.key0.is_default = 1;
+ ap_cfg->wep_cfg.key0.length = strlen(value);
+ memcpy(ap_cfg->wep_cfg.key0.key, value, strlen(value));
+ set_key = 1;
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol != PROTOCOL_WPA2
+ && ap_cfg->protocol != PROTOCOL_WPA) {
+ PRINTM(MWARN, "Warning! No KEY for open mode\n");
+ set_key = 1;
+ continue;
+ }
+ if (strlen(value) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(value) > MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PSK/PMK length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->wpa_cfg.length = strlen(value);
+ memcpy(ap_cfg->wpa_cfg.passphrase, value, strlen(value));
+ set_key = 1;
+ } else if (!strncmp(opt, "CHANNEL", strlen("CHANNEL"))) {
+ if (set_chan) {
+ PRINTM(MWARN, "Skipping CHANNEL, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MLAN_MAX_CHANNEL) {
+ PRINTM(MERROR, "AP_CFG: Channel must be between 1 and %d"
+ "(both included)\n", MLAN_MAX_CHANNEL);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->channel = atoi_ret;
+ set_chan = 1;
+ } else if (!strncmp(opt, "PREAMBLE", strlen("PREAMBLE"))) {
+ if (set_preamble) {
+ PRINTM(MWARN, "Skipping PREAMBLE, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* This is a READ only value from FW, so we can not set this and
+ pass it successfully */
+ set_preamble = 1;
+ } else if (!strncmp(opt, "MAX_SCB", strlen("MAX_SCB"))) {
+ if (set_scb) {
+ PRINTM(MWARN, "Skipping MAX_SCB, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MAX_STA_COUNT) {
+ PRINTM(MERROR, "AP_CFG: MAX_SCB must be between 1 to %d "
+ "(both included)\n", MAX_STA_COUNT);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->max_sta_count = (t_u16) atoi_ret;
+ set_scb = 1;
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set AP configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param data A pointer to user data
+ * @param len Length of buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len)
+{
+ int ret = 0;
+ static t_s8 buf[MAX_BUF_LEN];
+ mlan_uap_bss_param sys_config;
+ int restart = 0;
+
+ ENTER();
+
+#define MIN_AP_CFG_CMD_LEN 16 /* strlen("ASCII_CMD=AP_CFG") */
+ if ((len - 1) <= MIN_AP_CFG_CMD_LEN) {
+ PRINTM(MERROR, "Invalid length of command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(buf, 0, MAX_BUF_LEN);
+ memcpy(buf, data, len);
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ woal_uap_get_bss_param(priv, &sys_config, MOAL_IOCTL_WAIT);
+
+ /* Setting the default values */
+ sys_config.channel = 6;
+ sys_config.preamble_type = 0;
+
+ if ((ret = woal_uap_ap_cfg_parse_data(&sys_config, buf)))
+ goto done;
+
+ /* If BSS already started stop it first and restart after changing the
+ setting */
+ if (priv->bss_started == MTRUE) {
+ if ((ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)))
+ goto done;
+ restart = 1;
+ }
+
+ /* If the security mode is configured as WEP or WPA-PSK, it will disable
+ 11n automatically, and if configured as open(off) or wpa2-psk, it will
+ automatically enable 11n */
+ if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config.protocol == PROTOCOL_WPA)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Start the BSS after successful configuration */
+ if (restart)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS control ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param data BSS control type
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "ioctl bss ctrl=%d\n", data);
+ if ((data != UAP_BSS_START) && (data != UAP_BSS_STOP) &&
+ (data != UAP_BSS_RESET)) {
+ PRINTM(MERROR, "Invalid parameter: %d\n", data);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ switch (data) {
+ case UAP_BSS_START:
+ if (priv->bss_started == MTRUE) {
+ PRINTM(MWARN, "Warning: BSS already started!\n");
+ // goto done;
+ } else {
+ /* about to start bss: issue channel check */
+ woal_11h_channel_check_ioctl(priv);
+ }
+ bss->sub_command = MLAN_OID_BSS_START;
+ break;
+ case UAP_BSS_STOP:
+ if (priv->bss_started == MFALSE) {
+ PRINTM(MWARN, "Warning: BSS already stopped!\n");
+ // goto done;
+ }
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ break;
+ case UAP_BSS_RESET:
+ bss->sub_command = MLAN_OID_UAP_BSS_RESET;
+ woal_cancel_cac_block(priv);
+ break;
+ }
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data == UAP_BSS_STOP || data == UAP_BSS_RESET)
+ priv->bss_started = MFALSE;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ * @return N/A
+ */
+void
+woal_uap_set_multicast_list(struct net_device *dev)
+{
+ ENTER();
+
+ LEAVE();
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+ ENTER();
+ PRINTM(MIOCTL, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case UAP_HOSTCMD:
+ ret = woal_hostcmd_ioctl(dev, req);
+ break;
+ case UAP_IOCTL_CMD:
+ ret = woal_uap_ioctl(dev, req);
+ break;
+ case UAP_POWER_MODE:
+ ret = woal_uap_power_mode_ioctl(dev, req);
+ break;
+ case UAP_BSS_CTRL:
+ ret = woal_uap_bss_ctrl_ioctl(dev, req);
+ break;
+ case UAP_WAPI_MSG:
+ ret = woal_uap_set_wapi(dev, req);
+ break;
+ case UAP_BSS_CONFIG:
+ ret = woal_uap_bss_cfg_ioctl(dev, req);
+ break;
+ case UAP_STA_DEAUTH:
+ ret = woal_uap_sta_deauth_ioctl(dev, req);
+ break;
+ case UAP_RADIO_CTL:
+ ret = woal_uap_radio_ctl(dev, req);
+ break;
+ case UAP_GET_STA_LIST:
+ ret = woal_uap_get_sta_list_ioctl(dev, req);
+ break;
+ case UAP_CUSTOM_IE:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case UAP_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ default:
+#ifdef UAP_WEXT
+ ret = woal_uap_do_priv_ioctl(dev, req, cmd);
+#else
+ ret = -EOPNOTSUPP;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void
+woal_uap_get_version(moal_private * priv, char *version, int max_len)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_PROC_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "MOAL UAP VERSION: %s\n",
+ info->param.ver_ext.version_str);
+ snprintf(version, max_len, driver_version,
+ info->param.ver_ext.version_str);
+ }
+
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get uap statistics
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ustats A pointer to mlan_ds_uap_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_uap_get_stats(moal_private * priv, t_u8 wait_option,
+ mlan_ds_uap_stats * ustats)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (ustats)
+ memcpy(ustats, &info->param.ustats, sizeof(mlan_ds_uap_stats));
+#ifdef UAP_WEXT
+ priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc = info->param.ustats.ack_failure_count;
+#endif
+ }
+
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get system configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param wait_option Wait option
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_set_get_sys_config(moal_private * priv, t_u16 action, t_u8 wait_option,
+ mlan_uap_bss_param * sys_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ memcpy(&bss->param.bss_config, sys_cfg, sizeof(mlan_uap_bss_param));
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ memcpy(sys_cfg, &bss->param.bss_config, sizeof(mlan_uap_bss_param));
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set invalid data for each member of mlan_uap_bss_param
+ * structure
+ *
+ * @param config A pointer to mlan_uap_bss_param structure
+ *
+ * @return N/A
+ */
+void
+woal_set_sys_config_invalid_data(mlan_uap_bss_param * config)
+{
+ ENTER();
+
+ memset(config, 0, sizeof(mlan_uap_bss_param));
+ config->bcast_ssid_ctl = 0x7F;
+ config->radio_ctl = 0x7F;
+ config->dtim_period = 0x7F;
+ config->beacon_period = 0x7FFF;
+ config->tx_data_rate = 0x7FFF;
+ config->mcbc_data_rate = 0x7FFF;
+ config->tx_power_level = 0x7F;
+ config->tx_antenna = 0x7F;
+ config->rx_antenna = 0x7F;
+ config->pkt_forward_ctl = 0x7F;
+ config->max_sta_count = 0x7FFF;
+ config->auth_mode = 0x7F;
+ config->sta_ageout_timer = 0x7FFFFFFF;
+ config->pairwise_update_timeout = 0x7FFFFFFF;
+ config->pwk_retries = 0x7FFFFFFF;
+ config->groupwise_update_timeout = 0x7FFFFFFF;
+ config->gwk_retries = 0x7FFFFFFF;
+ config->mgmt_ie_passthru_mask = 0x7FFFFFFF;
+ config->ps_sta_ageout_timer = 0x7FFFFFFF;
+ config->rts_threshold = 0x7FFF;
+ config->frag_threshold = 0x7FFF;
+ config->retry_limit = 0x7FFF;
+ config->filter.filter_mode = 0x7FFF;
+ config->filter.mac_count = 0x7FFF;
+ config->wpa_cfg.rsn_protection = 0x7F;
+ config->wpa_cfg.gk_rekey_time = 0x7FFFFFFF;
+ config->enable_2040coex = 0x7F;
+ config->wmm_para.qos_info = 0x7F;
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.h b/drivers/net/wireless/sd8797/mlinux/moal_uap.h
new file mode 100644
index 000000000000..2667db84b8de
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.h
@@ -0,0 +1,410 @@
+/** @file moal_uap.h
+ *
+ * @brief This file contains uap driver specific defines etc.
+ *
+ * Copyright (C) 2009-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:
+ 02/02/2009: initial version
+********************************************************/
+
+#ifndef _MOAL_UAP_H
+#define _MOAL_UAP_H
+
+/** Maximum buffer length for WOAL_UAP_SET_GET_256_CHAR */
+#define MAX_BUF_LEN 256
+
+/** Private command ID to Host command */
+#define UAP_HOSTCMD (SIOCDEVPRIVATE + 1)
+/** Private command ID to send ioctl */
+#define UAP_IOCTL_CMD (SIOCDEVPRIVATE + 2)
+/** Updating ADDBA variables */
+#define UAP_ADDBA_PARA 0
+/** Updating priority table for AMPDU/AMSDU */
+#define UAP_AGGR_PRIOTBL 1
+/** Updating addbareject table */
+#define UAP_ADDBA_REJECT 2
+/** Get FW INFO */
+#define UAP_FW_INFO 4
+/** Updating Deep sleep variables */
+#define UAP_DEEP_SLEEP 3
+/** Tx data pause subcommand */
+#define UAP_TX_DATA_PAUSE 5
+/** sdcmd52 read write subcommand */
+#define UAP_SDCMD52_RW 6
+/** snmp mib subcommand */
+#define UAP_SNMP_MIB 7
+/** domain info subcommand */
+#define UAP_DOMAIN_INFO 8
+/** TX beamforming configuration */
+#define UAP_TX_BF_CFG 9
+#ifdef DFS_TESTING_SUPPORT
+/** dfs testing subcommand */
+#define UAP_DFS_TESTING 10
+#endif
+/** sub command ID to set/get Host Sleep configuration */
+#define UAP_HS_CFG 11
+/** sub command ID to set/get Host Sleep Parameters */
+#define UAP_HS_SET_PARA 12
+
+/** Management Frame Control Mask */
+#define UAP_MGMT_FRAME_CONTROL 13
+
+#define UAP_TX_RATE_CFG 14
+
+/** Subcommand ID to set/get antenna configuration */
+#define UAP_ANTENNA_CFG 15
+
+/** Private command ID to Power Mode */
+#define UAP_POWER_MODE (SIOCDEVPRIVATE + 3)
+
+/** Private command id to start/stop/reset bss */
+#define UAP_BSS_CTRL (SIOCDEVPRIVATE + 4)
+/** BSS START */
+#define UAP_BSS_START 0
+/** BSS STOP */
+#define UAP_BSS_STOP 1
+/** BSS RESET */
+#define UAP_BSS_RESET 2
+/** Band config 5GHz */
+#define BAND_CONFIG_5GHZ 0x01
+
+/** wapi_msg */
+typedef struct _wapi_msg
+{
+ /** message type */
+ t_u16 msg_type;
+ /** message len */
+ t_u16 msg_len;
+ /** message */
+ t_u8 msg[96];
+} wapi_msg;
+
+/* wapi key msg */
+typedef struct _wapi_key_msg
+{
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** pad */
+ t_u8 pad;
+ /** key id */
+ t_u8 key_id;
+ /** key */
+ t_u8 key[32];
+} wapi_key_msg;
+
+typedef struct _tx_rate_cfg_t
+{
+ /** sub command */
+ int subcmd;
+ /** Action */
+ int action;
+ /** Rate configured */
+ int rate;
+ /** Rate bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+} tx_rate_cfg_t;
+
+/** ant_cfg structure */
+typedef struct _ant_cfg_t
+{
+ /** Subcommand */
+ int subcmd;
+ /** Action */
+ int action;
+ /** TX mode configured */
+ int tx_mode;
+ /** RX mode configured */
+ int rx_mode;
+} ant_cfg_t;
+
+/** Private command ID to set wapi info */
+#define UAP_WAPI_MSG (SIOCDEVPRIVATE + 10)
+/** set wapi flag */
+#define P80211_PACKET_WAPIFLAG 0x0001
+/** set wapi key */
+#define P80211_PACKET_SETKEY 0x0003
+/** wapi mode psk */
+#define WAPI_MODE_PSK 0x04
+/** wapi mode certificate */
+#define WAPI_MODE_CERT 0x08
+
+/** radio control command */
+#define UAP_RADIO_CTL (SIOCDEVPRIVATE + 5)
+
+/** Private command ID to BSS config */
+#define UAP_BSS_CONFIG (SIOCDEVPRIVATE + 6)
+
+/** deauth station */
+#define UAP_STA_DEAUTH (SIOCDEVPRIVATE + 7)
+
+/** uap get station list */
+#define UAP_GET_STA_LIST (SIOCDEVPRIVATE + 11)
+
+/** Private command ID to set/get custom IE buffer */
+#define UAP_CUSTOM_IE (SIOCDEVPRIVATE + 13)
+
+/** HS WAKE UP event id */
+#define UAP_EVENT_ID_HS_WAKEUP 0x80000001
+/** HS_ACTIVATED event id */
+#define UAP_EVENT_ID_DRV_HS_ACTIVATED 0x80000002
+/** HS DEACTIVATED event id */
+#define UAP_EVENT_ID_DRV_HS_DEACTIVATED 0x80000003
+
+/** Host sleep flag set */
+#define HS_CFG_FLAG_GET 0
+/** Host sleep flag get */
+#define HS_CFG_FLAG_SET 1
+/** Host sleep flag for condition */
+#define HS_CFG_FLAG_CONDITION 2
+/** Host sleep flag for GPIO */
+#define HS_CFG_FLAG_GPIO 4
+/** Host sleep flag for Gap */
+#define HS_CFG_FLAG_GAP 8
+/** Host sleep flag for all */
+#define HS_CFG_FLAG_ALL 0x0f
+/** Host sleep mask to get condition */
+#define HS_CFG_CONDITION_MASK 0x0f
+
+/** ds_hs_cfg */
+typedef struct _ds_hs_cfg
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Bit0: 0 - Get, 1 Set
+ * Bit1: 1 - conditions is valid
+ * Bit2: 2 - gpio is valid
+ * Bit3: 3 - gap is valid
+ */
+ t_u32 flags;
+ /** Host sleep config condition */
+ /** Bit0: non-unicast data
+ * Bit1: unicast data
+ * Bit2: mac events
+ * Bit3: magic packet
+ */
+ t_u32 conditions;
+ /** GPIO */
+ t_u32 gpio;
+ /** Gap in milliseconds */
+ t_u32 gap;
+} ds_hs_cfg;
+
+/** Private command ID to get BSS type */
+#define UAP_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+/** addba_param */
+typedef struct _addba_param
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** block ack timeout for ADDBA request */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} addba_param;
+
+/** aggr_prio_tbl */
+typedef struct _aggr_prio_tbl
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} aggr_prio_tbl;
+
+/** addba_reject parameters */
+typedef struct _addba_reject_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** BA Reject paramters */
+ t_u8 addba_reject[MAX_NUM_TID];
+} addba_reject_para;
+
+/** fw_info */
+typedef struct _fw_info
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Get */
+ t_u32 action;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+} fw_info;
+
+typedef struct _tx_bf_cfg_para_hdr
+{
+ /** Sub command */
+ t_u32 subcmd;
+ /** Action: Set/Get */
+ t_u32 action;
+} tx_bf_cfg_para_hdr;
+
+/** sdcmd52rw parameters */
+typedef struct _sdcmd52_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Write /Read */
+ t_u32 action;
+ /** Command 52 paramters */
+ t_u8 cmd52_params[3];
+} sdcmd52_para;
+
+/** deep_sleep parameters */
+typedef struct _deep_sleep_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable deepsleep*/
+ t_u16 deep_sleep;
+ /** idle_time */
+ t_u16 idle_time;
+} deep_sleep_para;
+
+/** tx_data_pause parameters */
+typedef struct _tx_data_pause_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable Tx data pause*/
+ t_u16 txpause;
+ /** Max number of TX buffer allowed for all PS client*/
+ t_u16 txbufcnt;
+} tx_data_pause_para;
+
+/** mgmt_frame_ctrl */
+typedef struct _mgmt_frame_ctrl
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** mask */
+ t_u32 mask;
+} mgmt_frame_ctrl;
+
+typedef struct _snmp_mib_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** oid to set/get */
+ t_u16 oid;
+ /** length of oid value */
+ t_u16 oid_val_len;
+ /** oid value to set/get */
+ t_u8 oid_value[0];
+} snmp_mib_para;
+
+/** Max length for oid_value field */
+#define MAX_SNMP_VALUE_SIZE 128
+
+/** Oid for 802.11D enable/disable */
+#define OID_80211D_ENABLE 0x0009
+/** Oid for 802.11H enable/disable */
+#define OID_80211H_ENABLE 0x000a
+
+/** domain_info parameters */
+typedef struct _domain_info_param
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** domain_param TLV (incl. header) */
+ t_u8 tlv[0];
+} domain_info_para;
+
+/** DOMAIN_INFO param sizes */
+#define TLV_HEADER_LEN (2 + 2)
+#define SUB_BAND_LEN 3
+#define MAX_SUB_BANDS 40
+
+/** MAX domain TLV length */
+#define MAX_DOMAIN_TLV_LEN (TLV_HEADER_LEN + COUNTRY_CODE_LEN \
+ + (SUB_BAND_LEN * MAX_SUB_BANDS))
+
+#ifdef DFS_TESTING_SUPPORT
+/** dfs_testing parameters */
+typedef struct _dfs_testing_param
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** user CAC period (msec) */
+ t_u16 usr_cac_period;
+ /** user NOP period (sec) */
+ t_u16 usr_nop_period;
+ /** don't change channel on radar */
+ t_u8 no_chan_change;
+ /** fixed channel to change to on radar */
+ t_u8 fixed_new_chan;
+} dfs_testing_para;
+#endif
+
+void woal_uap_set_multicast_list(struct net_device *dev);
+int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+int woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data);
+void woal_uap_get_version(moal_private * priv, char *version, int max_len);
+mlan_status woal_uap_get_stats(moal_private * priv, t_u8 wait_option,
+ mlan_ds_uap_stats * ustats);
+#if defined(UAP_WEXT) || defined(UAP_CFG80211)
+extern struct iw_handler_def woal_uap_handler_def;
+struct iw_statistics *woal_get_uap_wireless_stats(struct net_device *dev);
+/** IOCTL function for wireless private IOCTLs */
+int woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+#endif
+/** Set invalid data for each member of mlan_uap_bss_param */
+void woal_set_sys_config_invalid_data(mlan_uap_bss_param * config);
+/** Set/Get system configuration parameters */
+mlan_status woal_set_get_sys_config(moal_private * priv,
+ t_u16 action, t_u8 wait_option,
+ mlan_uap_bss_param * sys_cfg);
+int woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len);
+mlan_status woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action);
+#ifdef UAP_WEXT
+void woal_ioctl_get_uap_info_resp(moal_private * priv, mlan_ds_get_info * info);
+int woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie,
+ int ie_len);
+#endif /* UAP_WEXT */
+#endif /* _MOAL_UAP_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
new file mode 100644
index 000000000000..18d18328d0ed
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
@@ -0,0 +1,1288 @@
+/** @file moal_uap_cfg80211.c
+ *
+ * @brief This file contains the functions for uAP CFG80211.
+ *
+ * Copyright (C) 2011-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.
+ *
+ */
+
+#include "moal_cfg80211.h"
+#include "moal_uap_cfg80211.h"
+
+/* these 3 function will be called in woal_cfg80211_wifi_direct_ops */
+int woal_cfg80211_add_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_set_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev);
+
+static int woal_uap_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
+
+static int woal_uap_cfg80211_connect(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+
+static int woal_uap_cfg80211_disconnect(struct wiphy *wiphy,
+ struct net_device *dev,
+ t_u16 reason_code);
+
+int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 * mac, struct station_info *stainfo);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+static const struct ieee80211_txrx_stypes
+ ieee80211_uap_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_MESH_POINT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+};
+#endif
+
+/** cfg80211 uAP operations */
+static struct cfg80211_ops woal_cfg80211_uap_ops = {
+ .add_virtual_intf = woal_cfg80211_add_virtual_intf,
+ .del_virtual_intf = woal_cfg80211_del_virtual_intf,
+ .set_channel = woal_cfg80211_set_channel,
+ .scan = woal_uap_cfg80211_scan,
+ .connect = woal_uap_cfg80211_connect,
+ .disconnect = woal_uap_cfg80211_disconnect,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .set_default_key = woal_cfg80211_set_default_key,
+ .add_beacon = woal_cfg80211_add_beacon,
+ .set_beacon = woal_cfg80211_set_beacon,
+ .del_beacon = woal_cfg80211_del_beacon,
+ .get_station = woal_uap_cfg80211_get_station,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ .mgmt_frame_register = woal_cfg80211_mgmt_frame_register,
+ .mgmt_tx = woal_cfg80211_mgmt_tx,
+#endif
+};
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
+/**
+ * @brief Verify RSN IE
+ *
+ * @param rsn_ie Pointer RSN IE
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8
+woal_check_rsn_ie(IEEEtypes_Rsn_t * rsn_ie, mlan_uap_bss_param * sys_config)
+{
+ int left = 0;
+ int count = 0;
+ int i = 0;
+ wpa_suite_auth_key_mgmt_t *key_mgmt = NULL;
+ left = rsn_ie->len + 2;
+ if (left < sizeof(IEEEtypes_Rsn_t))
+ return MFALSE;
+ sys_config->wpa_cfg.group_cipher = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 = 0;
+ /* check the group cipher */
+ switch (rsn_ie->group_cipher.type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ count = le16_to_cpu(rsn_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (rsn_ie->pairwise_cipher.list[i].type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(IEEEtypes_Rsn_t) + (count - 1) * sizeof(wpa_suite);
+ if (left < sizeof(wpa_suite_auth_key_mgmt_t))
+ return MFALSE;
+ key_mgmt =
+ (wpa_suite_auth_key_mgmt_t *) ((u8 *) rsn_ie + sizeof(IEEEtypes_Rsn_t) +
+ (count - 1) * sizeof(wpa_suite));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left <
+ (sizeof(wpa_suite_auth_key_mgmt_t) + (count - 1) * sizeof(wpa_suite)))
+ return MFALSE;
+
+ for (i = 0; i < count; i++) {
+ switch (key_mgmt->list[i].type) {
+ case RSN_AKM_8021X:
+ sys_config->key_mgmt = KEY_MGMT_EAP;
+ break;
+ case RSN_AKM_PSK:
+ sys_config->key_mgmt = KEY_MGMT_PSK;
+ break;
+ }
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Verify WPA IE
+ *
+ * @param wpa_ie Pointer WPA IE
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8
+woal_check_wpa_ie(IEEEtypes_Wpa_t * wpa_ie, mlan_uap_bss_param * sys_config)
+{
+ int left = 0;
+ int count = 0;
+ int i = 0;
+ wpa_suite_auth_key_mgmt_t *key_mgmt = NULL;
+ left = wpa_ie->len + 2;
+ if (left < sizeof(IEEEtypes_Wpa_t))
+ return MFALSE;
+ sys_config->wpa_cfg.group_cipher = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa = 0;
+ switch (wpa_ie->group_cipher.type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ count = le16_to_cpu(wpa_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (wpa_ie->pairwise_cipher.list[i].type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(IEEEtypes_Wpa_t) + (count - 1) * sizeof(wpa_suite);
+ if (left < sizeof(wpa_suite_auth_key_mgmt_t))
+ return MFALSE;
+ key_mgmt =
+ (wpa_suite_auth_key_mgmt_t *) ((u8 *) wpa_ie + sizeof(IEEEtypes_Wpa_t) +
+ (count - 1) * sizeof(wpa_suite));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left <
+ (sizeof(wpa_suite_auth_key_mgmt_t) + (count - 1) * sizeof(wpa_suite)))
+ return MFALSE;
+ for (i = 0; i < count; i++) {
+ switch (key_mgmt->list[i].type) {
+ case RSN_AKM_8021X:
+ sys_config->key_mgmt = KEY_MGMT_EAP;
+ break;
+ case RSN_AKM_PSK:
+ sys_config->key_mgmt = KEY_MGMT_PSK;
+ break;
+ }
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Find RSN/WPA IES
+ *
+ * @param ie Pointer IE buffer
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8
+woal_find_wpa_ies(t_u8 * ie, int len, mlan_uap_bss_param * sys_config)
+{
+ int bytes_left = len;
+ t_u8 *pcurrent_ptr = ie;
+ t_u16 total_ie_len;
+ t_u8 element_len;
+ t_u8 wpa2 = 0;
+ t_u8 wpa = 0;
+ t_u8 ret = MFALSE;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case RSN_IE:
+ wpa2 =
+ woal_check_rsn_ie((IEEEtypes_Rsn_t *) pcurrent_ptr, sys_config);
+ break;
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wpa_oui, sizeof(wpa_oui)))
+ wpa =
+ woal_check_wpa_ie((IEEEtypes_Wpa_t *) pcurrent_ptr,
+ sys_config);
+ break;
+ default:
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+ if (wpa && wpa2) {
+ sys_config->protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ ret = MTRUE;
+ } else if (wpa2) {
+ sys_config->protocol = PROTOCOL_WPA2;
+ ret = MTRUE;
+ } else if (wpa) {
+ sys_config->protocol = PROTOCOL_WPA;
+ ret = MTRUE;
+ }
+ return ret;
+}
+#endif
+
+/**
+ * @brief initialize AP or GO bss config
+ *
+ * @param priv A pointer to moal private structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_beacon_config(moal_private * priv,
+ struct beacon_parameters *params)
+{
+ int ret = 0;
+ mlan_uap_bss_param sys_config;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ int i = 0;
+#else
+ const t_u8 *ssid_ie = NULL;
+ struct ieee80211_mgmt *head = NULL;
+ t_u16 capab_info = 0;
+#endif
+
+ ENTER();
+
+ if (params == NULL) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->bss_type != MLAN_BSS_TYPE_UAP
+#ifdef WIFI_DIRECT_SUPPORT
+ && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ ) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Setting the default values */
+ sys_config.channel = 6;
+ sys_config.preamble_type = 0;
+
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ if (params->interval)
+ sys_config.beacon_period = params->interval;
+ if (params->dtim_period)
+ sys_config.dtim_period = params->dtim_period;
+ }
+ if (priv->channel)
+ sys_config.channel = priv->channel;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ if (!params->ssid || !params->ssid_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ memcpy(sys_config.ssid.ssid, params->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len));
+ sys_config.ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len);
+ if (params->hidden_ssid)
+ sys_config.bcast_ssid_ctl = 0;
+ else
+ sys_config.bcast_ssid_ctl = 1;
+ if (params->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ sys_config.auth_mode = MLAN_AUTH_MODE_SHARED;
+ else
+ sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+
+ for (i = 0; i < params->crypto.n_akm_suites; i++) {
+ switch (params->crypto.akm_suites[i]) {
+ case WLAN_AKM_SUITE_8021X:
+ sys_config.key_mgmt = KEY_MGMT_EAP;
+ if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
+ (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
+ sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.protocol = PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.protocol = PROTOCOL_WPA;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ sys_config.key_mgmt = KEY_MGMT_PSK;
+ if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
+ (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
+ sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.protocol = PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.protocol = PROTOCOL_WPA;
+ break;
+ }
+ }
+ sys_config.wpa_cfg.pairwise_cipher_wpa = 0;
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 = 0;
+ for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
+ switch (params->crypto.ciphers_pairwise[i]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP;
+ break;
+ }
+ }
+ switch (params->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ sys_config.protocol = PROTOCOL_STATIC_WEP;
+ sys_config.key_mgmt = KEY_MGMT_NONE;
+ sys_config.wpa_cfg.length = 0;
+ sys_config.wep_cfg.key0.key_index = priv->key_index;
+ sys_config.wep_cfg.key0.is_default = 1;
+ sys_config.wep_cfg.key0.length = priv->key_len;
+ memcpy(sys_config.wep_cfg.key0.key, priv->key_material,
+ priv->key_len);
+ }
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ sys_config.wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ }
+#else
+ /* Since in Android ICS 4.0.1's wpa_supplicant, there is no way to set ssid
+ when GO (AP) starts up, so get it from beacon head parameter TODO: right
+ now use hard code 24 -- ieee80211 header lenth, 12 -- fixed element
+ length for beacon */
+#define BEACON_IE_OFFSET 36
+ /* Find SSID in head SSID IE id: 0, right now use hard code */
+ ssid_ie = woal_parse_ie_tlv(params->head + BEACON_IE_OFFSET,
+ params->head_len - BEACON_IE_OFFSET, 0);
+ if (!ssid_ie) {
+ PRINTM(MERROR, "No ssid IE found.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (*(ssid_ie + 1) > 32) {
+ PRINTM(MERROR, "ssid len error: %d\n", *(ssid_ie + 1));
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(sys_config.ssid.ssid, ssid_ie + 2, *(ssid_ie + 1));
+ sys_config.ssid.ssid_len = *(ssid_ie + 1);
+ head = (struct ieee80211_mgmt *) params->head;
+ capab_info = le16_to_cpu(head->u.beacon.capab_info);
+ PRINTM(MIOCTL, "capab_info=0x%x\n", head->u.beacon.capab_info);
+ sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ /** For ICS, we don't support OPEN mode */
+ if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ sys_config.protocol = PROTOCOL_STATIC_WEP;
+ sys_config.key_mgmt = KEY_MGMT_NONE;
+ sys_config.wpa_cfg.length = 0;
+ sys_config.wep_cfg.key0.key_index = priv->key_index;
+ sys_config.wep_cfg.key0.is_default = 1;
+ sys_config.wep_cfg.key0.length = priv->key_len;
+ memcpy(sys_config.wep_cfg.key0.key, priv->key_material, priv->key_len);
+ } else {
+ /** Get cipher and key_mgmt from RSN/WPA IE */
+ if (capab_info & WLAN_CAPABILITY_PRIVACY) {
+ if (MFALSE ==
+ woal_find_wpa_ies(params->tail, params->tail_len,
+ &sys_config)) {
+ /* hard code setting to wpa2-psk */
+ sys_config.protocol = PROTOCOL_WPA2;
+ sys_config.key_mgmt = KEY_MGMT_PSK;
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ }
+ }
+ }
+#endif /* COMPAT_WIRELESS */
+ /* If the security mode is configured as WEP or WPA-PSK, it will disable
+ 11n automatically, and if configured as open(off) or wpa2-psk, it will
+ automatically enable 11n */
+ if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config.protocol == PROTOCOL_WPA))
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE);
+ else
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE);
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+static int
+woal_mon_open(struct net_device *ndev)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_mon_close(struct net_device *ndev)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_mon_set_mac_address(struct net_device *ndev, void *addr)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static void
+woal_mon_set_multicast_list(struct net_device *ndev)
+{
+ ENTER();
+ LEAVE();
+}
+
+static int
+woal_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int len_rthdr;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ unsigned short fc;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *prthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ monitor_iface *mon_if = netdev_priv(ndev);
+
+ if (mon_if == NULL || mon_if->base_ndev == NULL) {
+ goto fail;
+ }
+
+ ENTER();
+ /* check for not even having the fixed radiotap header part */
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) {
+ PRINTM(MERROR, "Invalid radiotap hdr length,"
+ "skb->len: %d\n", skb->len);
+ goto fail; /* too short to be possibly valid */
+ }
+
+ /* is it a header version we can trust to find length from? */
+ if (unlikely(prthdr->it_version))
+ goto fail; /* only version 0 is supported */
+
+ /* then there must be a radiotap header with a length we can use */
+ len_rthdr = ieee80211_get_radiotap_len(skb->data);
+
+ /* does the skb contain enough to deliver on the alleged length? */
+ if (unlikely(skb->len < len_rthdr)) {
+ PRINTM(MERROR, "Invalid data length," "skb->len: %d\n", skb->len);
+ goto fail; /* skb too short for claimed rt header extent */
+ }
+
+ /* Skip the ratiotap header */
+ skb_pull(skb, len_rthdr);
+
+ dot11_hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(dot11_hdr->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame which
+ has 4 MAC addresses */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ for two MAC addresses */
+ skb_pull(skb,
+ dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char *) skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr,
+ sizeof(src_mac_addr));
+
+ LEAVE();
+ return woal_hard_start_xmit(skb, mon_if->base_ndev);
+ }
+
+ fail:
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops woal_cfg80211_mon_if_ops = {
+ .ndo_open = woal_mon_open,
+ .ndo_start_xmit = woal_mon_hard_start_xmit,
+ .ndo_stop = woal_mon_close,
+ .ndo_set_mac_address = woal_mon_set_mac_address,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+ .ndo_set_rx_mode = woal_mon_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_mon_set_multicast_list,
+#endif
+};
+
+static void
+woal_mon_if_setup(struct net_device *dev)
+{
+ ENTER();
+ ether_setup(dev);
+ dev->netdev_ops = &woal_cfg80211_mon_if_ops;
+ dev->destructor = free_netdev;
+ LEAVE();
+}
+
+/**
+ * @brief Request the driver to add a monitor interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ * @param new_dev Netdevice to be passed out
+ *
+ * @return A pointer to net_device -- success, otherwise null
+ */
+static int
+woal_cfg80211_add_mon_if(struct wiphy *wiphy, char *name,
+ u32 * flags, struct vif_params *params,
+ struct net_device **new_dev)
+{
+ int ret;
+ struct net_device *ndev;
+ monitor_iface *mon_if;
+ moal_private *priv;
+
+ ENTER();
+
+ ASSERT_RTNL();
+
+ priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup, 1);
+ if (!ndev) {
+ PRINTM(MFATAL, "Init virtual ethernet device failed\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ dev_net_set(ndev, wiphy_net(wiphy));
+
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0) {
+ PRINTM(MFATAL, "Net device alloc name fail.\n");
+ goto fail;
+ }
+
+ memcpy(ndev->perm_addr, wiphy->perm_addr, ETH_ALEN);
+ memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
+
+ mon_if = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &mon_if->wdev;
+ mon_if->wdev.iftype = NL80211_IFTYPE_MONITOR;
+ mon_if->wdev.wiphy = wiphy;
+ memcpy(mon_if->ifname, ndev->name, IFNAMSIZ);
+
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ ndev->netdev_ops = &woal_cfg80211_mon_if_ops;
+
+ mon_if->priv = priv;
+ mon_if->mon_ndev = ndev;
+ mon_if->base_ndev = priv->netdev;
+ mon_if->radiotap_enabled = 1;
+ mon_if->flag = 1;
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ PRINTM(MFATAL, "register net_device failed, ret=%d\n", ret);
+ goto fail;
+ }
+
+ if (new_dev)
+ *new_dev = ndev;
+
+ fail:
+ if (ret && ndev)
+ free_netdev(ndev);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ *
+ * @return A pointer to net_device -- success, otherwise null
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+struct net_device *
+woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params)
+#else
+int
+woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params)
+#endif
+{
+ struct net_device *ndev = NULL;
+ int ret = 0;
+
+ ENTER();
+ PRINTM(MIOCTL, "add virtual intf: %d\n", type);
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ ret = woal_cfg80211_add_mon_if(wiphy, name, flags, params, &ndev);
+ break;
+ default:
+ PRINTM(MWARN, "Not supported if type: %d\n", type);
+ ret = -EFAULT;
+ break;
+ }
+ LEAVE();
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ if (ret)
+ return NULL;
+ else
+ return ndev;
+#else
+ return ret;
+#endif
+}
+
+/**
+ * @brief Request the driver to del a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev The pointer to net_device
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
+{
+ ENTER();
+
+ PRINTM(MIOCTL, "del virtual intf\n");
+ ASSERT_RTNL();
+ unregister_netdevice(dev);
+
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_uap_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ ENTER();
+
+ cfg80211_scan_done(request, MTRUE);
+
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_uap_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_uap_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ t_u16 reason_code)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief initialize AP or GO parameters
+
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_add_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "add beacon\n");
+ if (params != NULL) {
+ /* bss config */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_beacon_config(priv, params)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* set mgmt frame ies */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
+ params->tail,
+ params->tail_len,
+ NULL, 0, NULL, 0,
+ NULL, 0,
+ MGMT_MASK_BEACON
+#else
+ params->tail,
+ params->tail_len,
+ params->
+ proberesp_ies,
+ params->
+ proberesp_ies_len,
+ params->
+ assocresp_ies,
+ params->
+ assocresp_ies_len,
+ NULL, 0,
+ MGMT_MASK_BEACON
+ |
+ MGMT_MASK_PROBE_RESP
+ |
+ MGMT_MASK_ASSOC_RESP
+#endif
+ )) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* if the bss is stopped, then start it */
+ if (priv->bss_started == MFALSE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set AP or GO parameter
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "set beacon\n");
+ if (params != NULL) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
+ if (params->tail && params->tail_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv,
+ params->tail, params->tail_len,
+ NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_BEACON)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#else
+ if (params->beacon_ies && params->beacon_ies_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, params->tail,
+ params->tail_len, NULL, 0, NULL, 0,
+ NULL, 0, MGMT_MASK_BEACON)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (params->proberesp_ies && params->proberesp_ies_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0,
+ params->proberesp_ies,
+ params->proberesp_ies_len, NULL, 0,
+ NULL, 0, MGMT_MASK_PROBE_RESP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (params->assocresp_ies && params->assocresp_ies_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
+ params->assocresp_ies,
+ params->assocresp_ies_len, NULL, 0,
+ MGMT_MASK_ASSOC_RESP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset AP or GO parameters
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "del beacon\n");
+ /* if the bss is still running, then stop it */
+ if (priv->bss_started == MTRUE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_RESET)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* clear mgmt frame ies */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->cipher = 0;
+ priv->key_len = 0;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get station info
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac A pointer to station mac address
+ * @param stainfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 * mac, struct station_info *stainfo)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ int ret = -EFAULT;
+ int i = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *) ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ goto done;
+ }
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ if (!memcmp(info->param.sta_list.info[i].mac_address, mac, ETH_ALEN)) {
+ PRINTM(MIOCTL,
+ "Get station: %02x:%02x:%02x:%02x:%02x:%02x RSSI=%d\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ (int) info->param.sta_list.info[i].rssi);
+ stainfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_SIGNAL;
+ stainfo->inactive_time = 0;
+ stainfo->signal = info->param.sta_list.info[i].rssi;
+ ret = 0;
+ break;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Sets up the CFG802.11 specific HT capability fields
+ * with default values
+ *
+ * @param ht_info A pointer to ieee80211_sta_ht_cap structure
+ * @param ap_cfg A pointer to mlan_uap_bss_param
+ *
+ * @return N/A
+ */
+static void
+woal_cfg80211_setup_uap_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
+ mlan_uap_bss_param * ap_cfg)
+{
+ ENTER();
+
+ ht_info->ht_supported = true;
+ ht_info->ampdu_factor = ap_cfg->ampdu_param & (MBIT(1) | MBIT(0));
+ ht_info->ampdu_density =
+ ap_cfg->ampdu_param & (MBIT(4) | MBIT(3) | MBIT(2));
+
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ memcpy(ht_info->mcs.rx_mask, ap_cfg->supported_mcs_set,
+ sizeof(ht_info->mcs.rx_mask));
+
+ ht_info->cap = 0;
+ if (ap_cfg->ht_cap_info & MBIT(1)) /* 20/40 Mhz enable */
+ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if (ap_cfg->ht_cap_info & MBIT(4)) /* Green field supported */
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (ap_cfg->ht_cap_info & MBIT(5)) /* Short GI @ 20Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ if (ap_cfg->ht_cap_info & MBIT(6)) /* Short GI @ 40Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+ if (ap_cfg->ht_cap_info & MBIT(12)) /* DSS/CCK mode in 40MHz enable */
+ ht_info->cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the uAP wiphy
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option)
+{
+ struct wiphy *wiphy = priv->wdev->wiphy;
+ mlan_uap_bss_param ap_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ wait_option, &ap_cfg)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize parameters for 2GHz and 5GHz bands */
+ woal_cfg80211_setup_uap_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
+ &ap_cfg);
+ if (wiphy->bands[IEEE80211_BAND_5GHZ])
+ woal_cfg80211_setup_uap_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->
+ ht_cap, &ap_cfg);
+
+ /* Set retry limit count to wiphy */
+ wiphy->retry_long = (t_u8) ap_cfg.retry_limit;
+ wiphy->retry_short = (t_u8) ap_cfg.retry_limit;
+ wiphy->max_scan_ie_len = MAX_IE_SIZE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ wiphy->mgmt_stypes = ieee80211_uap_mgmt_stypes;
+#endif
+ /* Set RTS threshold to wiphy */
+ wiphy->rts_threshold = (t_u32) ap_cfg.rts_threshold;
+
+ /* Set fragment threshold to wiphy */
+ wiphy->frag_threshold = (t_u32) ap_cfg.frag_threshold;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Register the device with cfg80211
+ *
+ * @param dev A pointer to net_device structure
+ * @param bss_type BSS type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_uap_cfg80211(struct net_device * dev, t_u8 bss_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ void *wdev_priv = NULL;
+ struct wireless_dev *wdev = NULL;
+ mlan_fw_info fw_info;
+
+ ENTER();
+
+ /* Allocate wireless device */
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ PRINTM(MERROR, "Could not allocate wireless device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ /* Allocate wiphy */
+ wdev->wiphy = wiphy_new(&woal_cfg80211_uap_ops, sizeof(moal_private *));
+ if (!wdev->wiphy) {
+ PRINTM(MERROR, "Could not allocate wiphy device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+ if (bss_type == MLAN_BSS_TYPE_UAP) {
+ dev_set_name(&wdev->wiphy->dev, dev->name);
+ wdev->iftype = NL80211_IFTYPE_AP;
+ wdev->wiphy->interface_modes =
+ MBIT(NL80211_IFTYPE_AP) | MBIT(NL80211_IFTYPE_STATION) |
+ MBIT(NL80211_IFTYPE_MONITOR);
+ wdev->wiphy->max_scan_ssids = 10;
+ }
+
+ /* Make this wiphy known to this driver only */
+ wdev->wiphy->privid = mrvl_wiphy_privid;
+
+ /* Supported bands */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ if (MLAN_STATUS_SUCCESS ==
+ woal_request_get_fw_info(priv, MOAL_CMD_WAIT, &fw_info)) {
+ if (fw_info.fw_bands & BAND_A)
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+ }
+
+ /* Initialize cipher suits */
+ wdev->wiphy->cipher_suites = cfg80211_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
+
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* We are using custom domains */
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+
+ wdev->wiphy->reg_notifier = NULL; // TODO: woal_cfg80211_reg_notifier;
+
+ /* Set moal_private pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wdev->wiphy);
+
+ *(unsigned long *) wdev_priv = (unsigned long) priv;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) || defined(COMPAT_WIRELESS)
+ set_wiphy_dev(wdev->wiphy, (struct device *) priv->phandle->hotplug_device);
+#endif
+
+ if (wiphy_register(wdev->wiphy) < 0) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ } else {
+ PRINTM(MINFO, "Successfully registered wiphy device\n");
+ LEAVE();
+ return ret;
+ }
+
+ wiphy_unregister(wdev->wiphy);
+ err_wdev:
+ dev->ieee80211_ptr = NULL;
+ if (wdev && wdev->wiphy)
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h
new file mode 100644
index 000000000000..74c6f1a4e59b
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h
@@ -0,0 +1,30 @@
+/** @file moal_uap_cfg80211.h
+ *
+ * @brief This file contains the uAP CFG80211 specific defines.
+ *
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef _MOAL_UAP_CFG80211_H_
+#define _MOAL_UAP_CFG80211_H_
+
+#include "moal_uap.h"
+
+mlan_status woal_register_uap_cfg80211(struct net_device *dev, t_u8 bss_type);
+mlan_status woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option);
+
+#endif /* _MOAL_UAP_CFG80211_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c
new file mode 100644
index 000000000000..21f71cc4fe54
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c
@@ -0,0 +1,175 @@
+/** @file moal_uap_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ * Copyright (C) 2010-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:
+ 08/06/2010: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_uap_priv.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief ioctl function for wireless IOCTLs
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *) req;
+ int ret = 0;
+
+ ENTER();
+
+ switch (cmd) {
+ case WOAL_UAP_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_START:
+ break;
+ case WOAL_UAP_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_AP_BSS_START:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ break;
+ case WOAL_AP_BSS_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_UAP_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_VERSION:
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_UAP_VEREXT:
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_UAP_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_WL_FW_RELOAD:
+ break;
+ case WOAL_AP_SET_CFG:
+ ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer,
+ wrq->u.data.length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case WOAL_UAP_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_SET_GET_BSS_ROLE:
+ ret = woal_set_get_bss_role(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+#endif
+#endif
+ case WOAL_UAP_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_UAP_FROYO_START:
+ break;
+ case WOAL_UAP_FROYO_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_UAP_FROYO_AP_BSS_START:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ break;
+ case WOAL_UAP_FROYO_AP_BSS_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_UAP_FROYO_WL_FW_RELOAD:
+ break;
+ case WOAL_UAP_FROYO_AP_SET_CFG:
+ ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer,
+ wrq->u.data.length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_uap_info_resp(moal_private * priv, mlan_ds_get_info * info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc = info->param.ustats.ack_failure_count;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h
new file mode 100644
index 000000000000..fcd811efb168
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h
@@ -0,0 +1,194 @@
+/** @file moal_uap_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ * Copyright (C) 2010-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:
+ 08/06/2010: initial version
+************************************************************************/
+
+#ifndef _MOAL_UAP_PRIV_H_
+#define _MOAL_UAP_PRIV_H_
+
+/** Private command ID */
+#define WOAL_UAP_IOCTL 0x8BE0
+
+/** Private command to get/set 256 chars */
+#define WOAL_UAP_SET_GET_256_CHAR (WOAL_UAP_IOCTL + 1)
+/** Private command ID to FW reload */
+#define WOAL_WL_FW_RELOAD 1
+/** Private command ID to set AP configuration */
+#define WOAL_AP_SET_CFG 2
+
+/** Private command ID to set/get none */
+#define WOAL_UAP_SETNONE_GETNONE (WOAL_UAP_IOCTL + 2)
+/** Private command ID to start UAP */
+#define WOAL_UAP_START 1
+/** Private command ID to stop UAP */
+#define WOAL_UAP_STOP 2
+/** Private command ID to start AP BSS */
+#define WOAL_AP_BSS_START 3
+/** Private command ID to stop AP BSS */
+#define WOAL_AP_BSS_STOP 4
+
+/** Private command ID to set one int/get word char */
+#define WOAL_UAP_SETONEINT_GETWORDCHAR (WOAL_UAP_IOCTL + 3)
+/** Private command ID to get version */
+#define WOAL_UAP_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_UAP_VEREXT 2
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Private command ID to set one int/get one int */
+#define WOAL_UAP_SETONEINT_GETONEINT (WOAL_UAP_IOCTL + 5)
+/** Private command ID for set/get BSS role */
+#define WOAL_UAP_SET_GET_BSS_ROLE 1
+#endif
+#endif
+
+/** Private command ID for hostcmd */
+#define WOAL_UAP_HOST_CMD (WOAL_UAP_IOCTL + 17)
+
+/** The following command IDs are for Froyo app */
+/** Private command ID to start AP BSS */
+#define WOAL_UAP_FROYO_AP_BSS_START (WOAL_UAP_IOCTL + 24)
+/** Private command ID to stop AP BSS */
+#define WOAL_UAP_FROYO_AP_BSS_STOP (WOAL_UAP_IOCTL + 26)
+/** Private command ID to set AP config */
+#define WOAL_UAP_FROYO_AP_SET_CFG (WOAL_UAP_IOCTL + 27)
+/** Private command ID to start driver */
+#define WOAL_UAP_FROYO_START (WOAL_UAP_IOCTL + 28)
+/** Private command ID to reload FW */
+#define WOAL_UAP_FROYO_WL_FW_RELOAD (WOAL_UAP_IOCTL + 29)
+/** Private command ID to stop driver */
+#define WOAL_UAP_FROYO_STOP (WOAL_UAP_IOCTL + 30)
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_uap_priv_args[] = {
+ {
+ WOAL_UAP_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_UAP_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "start"},
+ {
+ WOAL_UAP_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "stop"},
+ {
+ WOAL_AP_BSS_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "bssstart"},
+ {
+ WOAL_AP_BSS_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "bssstop"},
+ {
+ WOAL_UAP_SETONEINT_GETWORDCHAR,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WOAL_UAP_VERSION,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {
+ WOAL_UAP_VEREXT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "verext"},
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ {
+ WOAL_UAP_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WOAL_UAP_SET_GET_BSS_ROLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "bssrole"},
+#endif
+#endif
+ {
+ WOAL_UAP_SET_GET_256_CHAR,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ ""},
+ {
+ WOAL_WL_FW_RELOAD,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "fwreload"},
+ {
+ WOAL_AP_SET_CFG,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "apcfg"},
+ {
+ WOAL_UAP_HOST_CMD,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {
+ WOAL_UAP_FROYO_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "START"},
+ {
+ WOAL_UAP_FROYO_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "STOP"},
+ {
+ WOAL_UAP_FROYO_AP_BSS_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "AP_BSS_START"},
+ {
+ WOAL_UAP_FROYO_AP_BSS_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "AP_BSS_STOP"},
+ {
+ WOAL_UAP_FROYO_WL_FW_RELOAD,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "WL_FW_RELOAD"},
+ {
+ WOAL_UAP_FROYO_AP_SET_CFG,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "AP_SET_CFG"},
+};
+
+#endif /* _MOAL_UAP_PRIV_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c
new file mode 100644
index 000000000000..eb1d048cafd6
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c
@@ -0,0 +1,1766 @@
+/** @file moal_uap_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ * Copyright (C) 2010-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:
+ 08/06/2010: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_wext.h"
+#include "moal_uap_priv.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+typedef struct _chan_to_freq_t
+{
+ /** Channel */
+ t_u16 channel;
+ /** Frequency */
+ t_u32 freq;
+ /** Band */
+ t_u8 band;
+} chan_to_freq_t;
+
+const chan_to_freq_t chan_to_freq[] = {
+ {1, 2412, 0},
+ {2, 2417, 0},
+ {3, 2422, 0},
+ {4, 2427, 0},
+ {5, 2432, 0},
+ {6, 2437, 0},
+ {7, 2442, 0},
+ {8, 2447, 0},
+ {9, 2452, 0},
+ {10, 2457, 0},
+ {11, 2462, 0},
+ {12, 2467, 0},
+ {13, 2472, 0},
+ {14, 2484, 0},
+ {183, 4915, 1},
+ {184, 4920, 1},
+ {185, 4925, 1},
+ {187, 4935, 1},
+ {188, 4940, 1},
+ {189, 4945, 1},
+ {192, 4960, 1},
+ {196, 4980, 1},
+ {7, 5035, 1},
+ {8, 5040, 1},
+ {9, 5045, 1},
+ {11, 5055, 1},
+ {12, 5060, 1},
+ {16, 5080, 1},
+ {34, 5170, 1},
+ {36, 5180, 1},
+ {38, 5190, 1},
+ {40, 5200, 1},
+ {42, 5210, 1},
+ {44, 5220, 1},
+ {46, 5230, 1},
+ {48, 5240, 1},
+ {52, 5260, 1},
+ {56, 5280, 1},
+ {60, 5300, 1},
+ {64, 5320, 1},
+ {100, 5500, 1},
+ {104, 5520, 1},
+ {108, 5540, 1},
+ {112, 5560, 1},
+ {116, 5580, 1},
+ {120, 5600, 1},
+ {124, 5620, 1},
+ {128, 5640, 1},
+ {132, 5660, 1},
+ {136, 5680, 1},
+ {140, 5700, 1},
+ {149, 5745, 1},
+ {153, 5765, 1},
+ {157, 5785, 1},
+ {161, 5805, 1},
+ {165, 5825, 1},
+};
+
+/** Convertion from frequency to channel */
+#define freq_to_chan(x) ((((x) - 2412) / 5) + 1)
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void
+woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Get frequency for channel in given band
+ *
+ * @param channel channel
+ * @param band band
+ *
+ * @return freq
+ */
+static int
+channel_to_frequency(t_u16 channel, t_u8 band)
+{
+ int i = 0;
+
+ ENTER();
+ for (i = 0; i < sizeof(chan_to_freq) / sizeof(chan_to_freq_t); i++) {
+ if (channel == chan_to_freq[i].channel && band == chan_to_freq[i].band) {
+ LEAVE();
+ return chan_to_freq[i].freq;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info, char *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ ENTER();
+ strcpy(cwrq, "IEEE 802.11-DS");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->bss_started) {
+ memcpy(awrq->sa_data, priv->current_addr, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Change the AP BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: uAP bss : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1],
+ (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3],
+ (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]);
+
+ /*
+ * Using this ioctl to start/stop the BSS, return if bss
+ * is already started/stopped.
+ */
+ if (memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ if (priv->bss_started == MFALSE)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ else
+ PRINTM(MINFO, "BSS is already started.\n");
+ } else {
+ /* zero_mac means bss_stop */
+ if (priv->bss_started == MTRUE)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ else
+ PRINTM(MINFO, "BSS is already stopped.\n");
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set frequency/channel
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
+ int ret = 0, chan = 0, i = 0;
+
+ ENTER();
+
+ ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (ap_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (sys_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ i = ap_cfg->num_of_chan;
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ /* If setting by frequency, convert to a channel */
+ if (fwrq->e == 1)
+ chan = freq_to_chan(fwrq->m / 100000);
+ else
+ chan = fwrq->m;
+ if (chan > 0 && chan < MLAN_MAX_CHANNEL)
+ sys_cfg->channel = chan;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+ for (i = 0; i < ap_cfg->num_of_chan; i++)
+ if (ap_cfg->chan_list[i].chan_number == chan)
+ break;
+ if (i == ap_cfg->num_of_chan) {
+ PRINTM(MERROR, "Channel %d is not supported\n", chan);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (sys_cfg)
+ kfree(sys_cfg);
+ if (ap_cfg)
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency and channel
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+ t_u8 band = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ band = ap_cfg.band_cfg & BAND_CONFIG_5GHZ;
+ fwrq->i = (long) ap_cfg.channel;
+ fwrq->m = (long) (channel_to_frequency(ap_cfg.channel, band)) * 100000;
+ fwrq->e = 1;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ ENTER();
+
+ switch (*uwrq) {
+ case IW_MODE_AUTO:
+ case IW_MODE_MASTER:
+ PRINTM(MINFO, "This is correct mode in AP mode\n");
+ break;
+ default:
+ PRINTM(MERROR, "Invalid mode for AP\n");
+ ret = -EINVAL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ ENTER();
+
+ *uwrq = IW_MODE_MASTER;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
+ wep_key *pkey = NULL;
+ int key_index = 0;
+
+ ENTER();
+
+ /* Check index */
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", key_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (ap_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (sys_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+ sys_cfg->wep_cfg.key0.key_index = 0;
+ sys_cfg->wep_cfg.key1.key_index = 1;
+ sys_cfg->wep_cfg.key2.key_index = 2;
+ sys_cfg->wep_cfg.key3.key_index = 3;
+
+ if (key_index >= 0 && key_index <= 3) {
+ if (key_index == 0)
+ pkey = &sys_cfg->wep_cfg.key0;
+ else if (key_index == 1)
+ pkey = &sys_cfg->wep_cfg.key1;
+ else if (key_index == 2)
+ pkey = &sys_cfg->wep_cfg.key2;
+ else if (key_index == 3)
+ pkey = &sys_cfg->wep_cfg.key3;
+ }
+
+ if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length);
+ ret = -E2BIG;
+ goto done;
+ }
+ if (key_index < 0) {
+ /* Get current default key index */
+ if (ap_cfg->wep_cfg.key0.is_default)
+ pkey = &sys_cfg->wep_cfg.key0;
+ if (ap_cfg->wep_cfg.key1.is_default)
+ pkey = &sys_cfg->wep_cfg.key1;
+ if (ap_cfg->wep_cfg.key2.is_default)
+ pkey = &sys_cfg->wep_cfg.key2;
+ if (ap_cfg->wep_cfg.key3.is_default)
+ pkey = &sys_cfg->wep_cfg.key3;
+ }
+
+ sys_cfg->protocol = PROTOCOL_STATIC_WEP;
+ memcpy(pkey->key, extra, dwrq->length);
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ pkey->length = MAX_WEP_KEY_SIZE;
+ else
+ pkey->length = MIN_WEP_KEY_SIZE;
+ /* Set current key index as default */
+ pkey->is_default = MTRUE;
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sys_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * Do we want to just set the transmit key index ?
+ */
+ if (key_index < 0) {
+ PRINTM(MINFO, "*** iwconfig mlanX key on ***\n");
+ } else {
+ /* Get current key configuration at key_index */
+ if (key_index == 0)
+ memcpy(pkey, &ap_cfg->wep_cfg.key0, sizeof(wep_key));
+ if (key_index == 1)
+ memcpy(pkey, &ap_cfg->wep_cfg.key1, sizeof(wep_key));
+ if (key_index == 2)
+ memcpy(pkey, &ap_cfg->wep_cfg.key2, sizeof(wep_key));
+ if (key_index == 3)
+ memcpy(pkey, &ap_cfg->wep_cfg.key3, sizeof(wep_key));
+ /* Set current key index as default */
+ pkey->is_default = MTRUE;
+ }
+ }
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ switch (dwrq->flags & 0xf000) {
+ case IW_ENCODE_RESTRICTED:
+ /* iwconfig mlanX restricted key [1] */
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ break;
+ case IW_ENCODE_OPEN:
+ /* iwconfig mlanX key [2] open */
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ break;
+ case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
+ default:
+ /* iwconfig mlanX key [2] open restricted */
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (sys_cfg)
+ kfree(sys_cfg);
+ if (ap_cfg)
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+ wep_key *pkey = NULL;
+ mlan_uap_bss_param ap_cfg;
+ int ret = 0;
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (ap_cfg.auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+
+ switch (ap_cfg.protocol) {
+ case PROTOCOL_NO_SECURITY:
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ break;
+ case PROTOCOL_STATIC_WEP:
+ if (ap_cfg.wep_cfg.key0.is_default)
+ pkey = &ap_cfg.wep_cfg.key0;
+ else if (ap_cfg.wep_cfg.key1.is_default)
+ pkey = &ap_cfg.wep_cfg.key1;
+ else if (ap_cfg.wep_cfg.key2.is_default)
+ pkey = &ap_cfg.wep_cfg.key2;
+ else if (ap_cfg.wep_cfg.key3.is_default)
+ pkey = &ap_cfg.wep_cfg.key3;
+ if (pkey) {
+ dwrq->flags |= (pkey->key_index + 1);
+ dwrq->length = pkey->length;
+ memcpy(extra, pkey->key, pkey->length);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ ret = -EFAULT;
+ }
+ break;
+ case PROTOCOL_WPA:
+ case PROTOCOL_WPA2:
+ case PROTOCOL_WPA2_MIXED:
+ memcpy(extra, ap_cfg.wpa_cfg.passphrase, ap_cfg.wpa_cfg.length);
+ dwrq->length = ap_cfg.wpa_cfg.length;
+ dwrq->flags |= 1;
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ break;
+ default:
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ break;
+ }
+ dwrq->flags |= IW_ENCODE_NOKEY;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+#if (WIRELESS_EXT >= 18)
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param sys_cfg;
+ IEEEtypes_Header_t *tlv = NULL;
+ int tlv_hdr_len = sizeof(IEEEtypes_Header_t), tlv_buf_left = 0;
+ int ret = 0;
+
+ ENTER();
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ tlv_buf_left = dwrq->length;
+ tlv = (IEEEtypes_Header_t *) extra;
+ while (tlv_buf_left >= tlv_hdr_len) {
+ if (tlv->element_id == WPA_IE) {
+ sys_cfg.protocol |= PROTOCOL_WPA;
+ if (priv->pairwise_cipher == CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ PRINTM(MINFO, "Set IE Cipher TKIP\n");
+ }
+ if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ PRINTM(MINFO, "Set IE Cipher CCMP\n");
+ }
+ if (priv->pairwise_cipher == (CIPHER_TKIP | CIPHER_AES_CCMP)) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_TKIP | CIPHER_AES_CCMP;
+ PRINTM(MINFO, "Set IE Cipher TKIP + CCMP\n");
+ }
+ memcpy(priv->bcn_ie_buf + priv->bcn_ie_len,
+ ((t_u8 *) tlv), sizeof(IEEEtypes_Header_t) + tlv->len);
+ priv->bcn_ie_len += sizeof(IEEEtypes_Header_t) + tlv->len;
+ }
+ if (tlv->element_id == RSN_IE) {
+ sys_cfg.protocol |= PROTOCOL_WPA2;
+ if (priv->pairwise_cipher == CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
+ }
+ if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ }
+ if (priv->pairwise_cipher == (CIPHER_TKIP | CIPHER_AES_CCMP)) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ }
+ memcpy(priv->bcn_ie_buf + priv->bcn_ie_len,
+ ((t_u8 *) tlv), sizeof(IEEEtypes_Header_t) + tlv->len);
+ priv->bcn_ie_len += sizeof(IEEEtypes_Header_t) + tlv->len;
+ }
+ if (priv->group_cipher == CIPHER_TKIP)
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
+ if (priv->group_cipher == CIPHER_AES_CCMP)
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ tlv_buf_left -= (tlv_hdr_len + tlv->len);
+ tlv = (IEEEtypes_Header_t *) ((t_u8 *) tlv + tlv_hdr_len + tlv->len);
+ }
+ sys_cfg.key_mgmt = priv->uap_key_mgmt;
+ if (sys_cfg.key_mgmt & KEY_MGMT_PSK)
+ sys_cfg.key_mgmt_operation |= 0x01;
+ if (sys_cfg.key_mgmt & KEY_MGMT_EAP)
+ sys_cfg.key_mgmt_operation |= 0x03;
+
+ if (sys_cfg.protocol) {
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP configuration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->pairwise_cipher = 0;
+ priv->group_cipher = 0;
+
+ /* custom IE command to set priv->bcn_ie_buf */
+ if (MLAN_STATUS_SUCCESS !=
+#define UAP_RSN_MASK (BIT(8) | BIT(5) | BIT(1) | BIT(3))
+ woal_set_get_custom_ie(priv, UAP_RSN_MASK, priv->bcn_ie_buf,
+ priv->bcn_ie_len)) {
+ PRINTM(MERROR, "Error setting wpa-rsn IE\n");
+ ret = -EFAULT;
+ }
+ } else if (dwrq->length == 0) {
+ /* custom IE command to re-set priv->bcn_ie_buf */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_custom_ie(priv, 0, priv->bcn_ie_buf,
+ priv->bcn_ie_len)) {
+ PRINTM(MERROR, "Error resetting wpa-rsn IE\n");
+ ret = -EFAULT;
+ }
+ priv->bcn_ie_len = 0;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_uap_bss_param sys_cfg;
+ wep_key *pwep_key = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ pkey_material = (t_u8 *) (ext + 1);
+ /* Disable Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sys_cfg.protocol = PROTOCOL_NO_SECURITY;
+ } else if (ext->alg == IW_ENCODE_ALG_WEP) {
+ sys_cfg.protocol = PROTOCOL_STATIC_WEP;
+ /* Set WEP key */
+ switch (key_index) {
+ case 0:
+ pwep_key = &sys_cfg.wep_cfg.key0;
+ break;
+ case 1:
+ pwep_key = &sys_cfg.wep_cfg.key1;
+ break;
+ case 2:
+ pwep_key = &sys_cfg.wep_cfg.key2;
+ break;
+ case 3:
+ pwep_key = &sys_cfg.wep_cfg.key3;
+ break;
+ }
+ pwep_key->key_index = key_index;
+ pwep_key->is_default = MTRUE;
+ pwep_key->length = ext->key_len;
+ memcpy(pwep_key->key, pkey_material, ext->key_len);
+ } else {
+ /* Set GTK/PTK key */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_len = ext->key_len;
+ sec->param.encrypt_key.key_index = key_index;
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ memcpy(sec->param.encrypt_key.mac_addr, ext->addr.sa_data, ETH_ALEN);
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Uap Rx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Uap Tx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ PRINTM(MIOCTL,
+ "set uap wpa key key_index=%d, key_len=%d key_flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n",
+ key_index, ext->key_len, sec->param.encrypt_key.key_flags,
+ sec->param.encrypt_key.mac_addr[0],
+ sec->param.encrypt_key.mac_addr[1],
+ sec->param.encrypt_key.mac_addr[2],
+ sec->param.encrypt_key.mac_addr[3],
+ sec->param.encrypt_key.mac_addr[4],
+ sec->param.encrypt_key.mac_addr[5]);
+ DBG_HEXDUMP(MCMD_D, "uap wpa key", pkey_material, ext->key_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ /* Cipher set will be done in set generic IE */
+ priv->pairwise_cipher = ext->alg;
+ priv->group_cipher = ext->alg;
+ goto done; /* No AP configuration */
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_mlme(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *dwrq, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ds_get_info *pinfo = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sta_list *sta_list = NULL;
+ const t_u8 bc_addr[] = { 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF };
+ t_u8 sta_addr[ETH_ALEN];
+ int ret = 0, i;
+
+ ENTER();
+
+ memset(sta_addr, 0, ETH_ALEN);
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+ memcpy(sta_addr, (t_u8 *) mlme->addr.sa_data, ETH_ALEN);
+ PRINTM(MIOCTL, "Deauth station: %02x:%02x:%02x:%02x:%02x:%02x, "
+ "reason=%d\n", sta_addr[0], sta_addr[1], sta_addr[2],
+ sta_addr[3], sta_addr[4], sta_addr[5], mlme->reason_code);
+
+ /* FIXME: For flushing all stations we need to use zero MAC, but right
+ now the FW does not support this. So, manually delete each one
+ individually. */
+ /* If deauth all station, get the connected STA list first */
+ if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) {
+ PRINTM(MIOCTL, "Deauth all stations\n");
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pinfo = (mlan_ds_get_info *) req->pbuf;
+ pinfo->sub_command = MLAN_OID_UAP_STA_LIST;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sta_list =
+ (mlan_ds_sta_list *) kmalloc(sizeof(mlan_ds_sta_list),
+ GFP_KERNEL);
+ if (sta_list == NULL) {
+ PRINTM(MERROR, "Memory allocation failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ memcpy(sta_list, &pinfo->param.sta_list, sizeof(mlan_ds_sta_list));
+ if (req)
+ kfree(req);
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) {
+ for (i = 0; i < sta_list->sta_count; i++) {
+ memcpy(bss->param.deauth_param.mac_addr,
+ sta_list->info[i].mac_address, ETH_ALEN);
+ bss->param.deauth_param.reason_code = mlme->reason_code;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ memcpy(bss->param.deauth_param.mac_addr, sta_addr, ETH_ALEN);
+ bss->param.deauth_param.reason_code = mlme->reason_code;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ if (sta_list)
+ kfree(sta_list);
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param sys_cfg;
+
+ ENTER();
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ /* Rest are not supported now */
+ if (vwrq->value & IW_AUTH_CIPHER_NONE);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104);
+ else if (vwrq->value == IW_AUTH_CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
+ priv->pairwise_cipher = CIPHER_TKIP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP\n");
+ } else if (vwrq->value == IW_AUTH_CIPHER_CCMP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ priv->pairwise_cipher = CIPHER_AES_CCMP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher CCMP\n");
+ } else if (vwrq->value == (IW_AUTH_CIPHER_TKIP | IW_AUTH_CIPHER_CCMP)) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ priv->pairwise_cipher = (CIPHER_TKIP | CIPHER_AES_CCMP);
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP + CCMP\n");
+ }
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ /* Rest are not supported now */
+ if (vwrq->value & IW_AUTH_CIPHER_NONE);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104);
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
+ priv->group_cipher = CIPHER_TKIP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP\n");
+ } else if (vwrq->value & IW_AUTH_CIPHER_CCMP) {
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ priv->group_cipher = CIPHER_AES_CCMP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher CCMP\n");
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ sys_cfg.auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ sys_cfg.auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ break;
+ case IW_AUTH_WPA_VERSION:
+ switch (vwrq->value) {
+ case IW_AUTH_WPA_VERSION_DISABLED:
+ sys_cfg.protocol = PROTOCOL_NO_SECURITY;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA:
+ sys_cfg.protocol = PROTOCOL_WPA;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA2:
+ sys_cfg.protocol = PROTOCOL_WPA2;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2:
+ sys_cfg.protocol = PROTOCOL_WPA2_MIXED;
+ break;
+ default:
+ break;
+ }
+ priv->uap_protocol = sys_cfg.protocol;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ switch (vwrq->value) {
+ case IW_AUTH_KEY_MGMT_802_1X:
+ sys_cfg.key_mgmt |= KEY_MGMT_EAP;
+ priv->uap_key_mgmt |= KEY_MGMT_EAP;
+ break;
+ case IW_AUTH_KEY_MGMT_PSK:
+ sys_cfg.key_mgmt |= KEY_MGMT_PSK;
+ priv->uap_key_mgmt |= KEY_MGMT_PSK;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ LEAVE();
+ return -EOPNOTSUPP; /* No AP configuration */
+ }
+ if (!sys_cfg.key_mgmt)
+ sys_cfg.key_mgmt = priv->uap_key_mgmt;
+ if (sys_cfg.key_mgmt & KEY_MGMT_PSK)
+ sys_cfg.key_mgmt_operation |= 0x01;
+ if (sys_cfg.key_mgmt & KEY_MGMT_EAP)
+ sys_cfg.key_mgmt_operation |= 0x03;
+ if (!sys_cfg.protocol)
+ sys_cfg.protocol = priv->uap_protocol;
+
+ /* Set AP configuration */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ if (ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (ap_cfg.auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (ap_cfg.auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (ap_cfg.protocol == PROTOCOL_WPA ||
+ ap_cfg.protocol == PROTOCOL_WPA2 ||
+ ap_cfg.protocol == PROTOCOL_WPA2_MIXED)
+ vwrq->value = 1;
+ else
+ vwrq->value = 0;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ if (ap_cfg.key_mgmt & KEY_MGMT_EAP)
+ vwrq->value |= IW_AUTH_KEY_MGMT_802_1X;
+ if (ap_cfg.key_mgmt & KEY_MGMT_PSK)
+ vwrq->value |= IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return 0;
+}
+#endif /* WE >= 18 */
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+ struct iw_range *range = (struct iw_range *) extra;
+ t_u8 band = 0;
+ int i;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ range->num_bitrates = MAX_DATA_RATES;
+ for (i = 0; i < MIN(MAX_DATA_RATES, IW_MAX_BITRATES) &&
+ ap_cfg.rates[i]; i++) {
+ range->bitrate[i] = (ap_cfg.rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n",
+ IW_MAX_BITRATES, range->num_bitrates);
+
+ range->num_frequency = MIN(ap_cfg.num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long) ap_cfg.chan_list[i].chan_number;
+ band = ap_cfg.chan_list[i].band_config_type & BAND_CONFIG_5GHZ;
+ range->freq[i].m =
+ (long) channel_to_frequency(ap_cfg.chan_list[i].chan_number,
+ band) * 100000;
+ range->freq[i].e = 1;
+ }
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+#if (WIRELESS_EXT >= 18)
+ if (ap_cfg.protocol & PROTOCOL_WPA)
+ range->enc_capa |= IW_ENC_CAPA_WPA;
+ if (ap_cfg.protocol & PROTOCOL_WPA2)
+ range->enc_capa |= IW_ENC_CAPA_WPA2;
+ if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP ||
+ ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP)
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
+ if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP ||
+ ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP)
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
+#endif
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set priv command
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_priv(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param sys_cfg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ /* Set the SSID */
+#if WIRELESS_EXT > 20
+ sys_cfg.ssid.ssid_len = dwrq->length;
+#else
+ sys_cfg.ssid.ssid_len = dwrq->length - 1;
+#endif
+
+ memcpy(sys_cfg.ssid.ssid, extra,
+ MIN(sys_cfg.ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
+ if (!sys_cfg.ssid.ssid_len || sys_cfg.ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Requested new SSID = %s\n",
+ (sys_cfg.ssid.ssid_len > 0) ? (char *) sys_cfg.ssid.ssid : "NULL");
+
+ /* Set AP configuration */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (priv->bss_started) {
+ dwrq->length = MIN(dwrq->length, ap_cfg.ssid.ssid_len);
+ memcpy(extra, ap_cfg.ssid.ssid, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ dwrq->flags = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) woal_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler) woal_set_priv, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler) woal_set_wap, /* SIOCSIWAP */
+ (iw_handler) woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler) woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler) NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler) woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler) NULL, /* SIOCSIWNICKN */
+ (iw_handler) NULL, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCSIWRATE */
+ (iw_handler) NULL, /* SIOCGIWRATE */
+ (iw_handler) NULL, /* SIOCSIWRTS */
+ (iw_handler) NULL, /* SIOCGIWRTS */
+ (iw_handler) NULL, /* SIOCSIWFRAG */
+ (iw_handler) NULL, /* SIOCGIWFRAG */
+ (iw_handler) NULL, /* SIOCSIWTXPOW */
+ (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) NULL, /* SIOCSIWRETRY */
+ (iw_handler) NULL, /* SIOCGIWRETRY */
+ (iw_handler) woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) NULL, /* SIOCSIWPOWER */
+ (iw_handler) NULL, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler) woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** wlan_handler_def */
+struct iw_handler_def woal_uap_handler_def = {
+ num_standard:sizeof(woal_handler) / sizeof(iw_handler),
+ num_private:sizeof(woal_private_handler) / sizeof(iw_handler),
+ num_private_args:sizeof(woal_uap_priv_args) /
+ sizeof(struct iw_priv_args),
+ standard:(iw_handler *) woal_handler,
+ private:(iw_handler *) woal_private_handler,
+ private_args:(struct iw_priv_args *) woal_uap_priv_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats:woal_get_uap_wireless_stats,
+#endif
+};
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+woal_get_uap_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u16 wait_option = MOAL_NO_WAIT;
+
+ ENTER();
+
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (write_can_lock(&dev_base_lock)
+ && (!in_atomic() || current->exit_state))
+ wait_option = MOAL_WSTATS_WAIT;
+
+ priv->w_stats.qual.qual = 0;
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.discard.code = 0;
+ priv->w_stats.status = IW_MODE_MASTER;
+ woal_uap_get_stats(priv, wait_option, NULL);
+
+ LEAVE();
+ return &priv->w_stats;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_wext.c
new file mode 100644
index 000000000000..a967c939f009
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.c
@@ -0,0 +1,3051 @@
+/** @file moal_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ * 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/21/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+
+#ifdef STA_SUPPORT
+/** Approximate amount of data needed to pass a scan result back to iwlist */
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+ + MLAN_MAX_SSID_LENGTH \
+ + IW_EV_UINT_LEN \
+ + IW_EV_FREQ_LEN \
+ + IW_EV_QUAL_LEN \
+ + MLAN_MAX_SSID_LENGTH \
+ + IW_EV_PARAM_LEN \
+ + 40) /* 40 for WPAIE */
+/** Macro for minimum size of scan buffer */
+#define MIN_ACCEPTED_GET_SCAN_BUF 8000
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function validates a SSID as being able to be printed
+ *
+ * @param pssid SSID structure to validate
+ *
+ * @return MTRUE or MFALSE
+ */
+static BOOLEAN
+woal_ssid_valid(mlan_802_11_ssid * pssid)
+{
+#ifdef ASCII_SSID_CHECK
+ unsigned int ssid_idx;
+
+ ENTER();
+
+ for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++) {
+ if ((pssid->ssid[ssid_idx] < 0x20) || (pssid->ssid[ssid_idx] > 0x7e)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ LEAVE();
+#endif
+ return MTRUE;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+static t_s32
+woal_ssid_cmp(mlan_802_11_ssid * ssid1, mlan_802_11_ssid * ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void
+woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Convert RSSI to quality
+ *
+ * @param rssi RSSI in dBm
+ *
+ * @return Quality of the link (0-5)
+ */
+static t_u8
+woal_rssi_to_quality(t_s16 rssi)
+{
+/** Macro for RSSI range */
+#define MOAL_RSSI_NO_SIGNAL -90
+#define MOAL_RSSI_VERY_LOW -80
+#define MOAL_RSSI_LOW -70
+#define MOAL_RSSI_GOOD -60
+#define MOAL_RSSI_VERY_GOOD -50
+#define MOAL_RSSI_INVALID 0
+ if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID)
+ return 0;
+ else if (rssi <= MOAL_RSSI_VERY_LOW)
+ return 1;
+ else if (rssi <= MOAL_RSSI_LOW)
+ return 2;
+ else if (rssi <= MOAL_RSSI_GOOD)
+ return 3;
+ else if (rssi <= MOAL_RSSI_VERY_GOOD)
+ return 4;
+ else
+ return 5;
+}
+
+/**
+ * @brief Set Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ /*
+ * Check the size of the string
+ */
+ if (dwrq->length > 16) {
+ LEAVE();
+ return -E2BIG;
+ }
+ memset(priv->nick_name, 0, sizeof(priv->nick_name));
+ memcpy(priv->nick_name, extra, dwrq->length);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ /*
+ * Get the Nick Name saved
+ */
+ strncpy(extra, (char *) priv->nick_name, 16);
+ extra[16] = '\0';
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /*
+ * Push it out !
+ */
+ dwrq->length = strlen(extra) + 1;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info, char *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ ENTER();
+ strcpy(cwrq, "IEEE 802.11-DS");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ /*
+ * If setting by frequency, convert to a channel
+ */
+ if (fwrq->e == 1) {
+ long f = fwrq->m / 100000;
+ bss->param.bss_chan.freq = f;
+ } else
+ bss->param.bss_chan.channel = fwrq->m;
+
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(priv, bss->param.bss_chan.channel))
+ ret = -EFAULT;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fwrq->m = (long) bss->param.bss_chan.freq * 100000;
+ fwrq->i = (long) bss->param.bss_chan.channel;
+ fwrq->e = 1;
+ fwrq->flags = IW_FREQ_FIXED;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq Wireless mode to set
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (*uwrq) {
+ case IW_MODE_INFRA:
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ break;
+ case IW_MODE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ break;
+ case IW_MODE_AUTO:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (bss_info.media_connected == MTRUE) {
+ memcpy(awrq->sa_data, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * NOTE: Scan should be issued by application before this function is called
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = { 255, 255, 255, 255, 255, 255 };
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ssid_bssid ssid_bssid;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1],
+ (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3],
+ (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+#endif
+
+ /* zero_mac means disconnect */
+ if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ goto done;
+ }
+
+ /* Broadcast MAC means search for best network */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ /* Check if we are already assoicated to the AP */
+ if (bss_info.media_connected == MTRUE) {
+ if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
+ goto done;
+ /* disconnect before try to assoicate to the new AP */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ }
+ memcpy(&ssid_bssid.bssid, awrq->sa_data, ETH_ALEN);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_find_best_network(priv,
+ MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR, "ASSOC: WAP: MAC address not found in BSSID List\n");
+ ret = -ENETUNREACH;
+ goto done;
+ }
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
+ MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+#endif /* REASSOCIATION */
+
+ done:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ *uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_set_sens(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -1
+ */
+static int
+woal_get_sens(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = -1;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_power_cfg_t power_cfg;
+
+ ENTER();
+ if (vwrq->disabled) {
+ woal_set_radio(priv, 0);
+ goto done;
+ }
+ woal_set_radio(priv, 1);
+
+ if (!vwrq->fixed)
+ power_cfg.is_power_auto = 1;
+ else {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = vwrq->value;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_power_cfg_t power_cfg;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&power_cfg, 0, sizeof(mlan_power_cfg_t));
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = power_cfg.power_level;
+ if (power_cfg.is_power_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ if (bss_info.radio_on) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+ vwrq->disabled = 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, disabled;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ disabled = vwrq->disabled;
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
+ MLAN_ACT_SET, &disabled,
+ vwrq->flags)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, ps_mode;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
+ MLAN_ACT_GET, &ps_mode,
+ 0)) {
+ ret = -EFAULT;
+ }
+
+ if (ps_mode)
+ vwrq->disabled = 0;
+ else
+ vwrq->disabled = 1;
+
+ vwrq->value = 0;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, retry_val = vwrq->value;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (vwrq->flags == IW_RETRY_LIMIT) {
+ /*
+ * The MAC has a 4-bit Total_Tx_Count register
+ * Total_Tx_Count = 1 + Tx_Retry_Count
+ */
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, &retry_val)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int retry_val, ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &retry_val)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->disabled = 0;
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Get Tx retry count */
+ vwrq->value = retry_val;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ int index = 0;
+ t_u32 auth_mode = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Check index */
+ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ sec->param.encrypt_key.key_len = 0;
+ if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (index < 0)
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ else
+ sec->param.encrypt_key.key_index = index;
+ memcpy(sec->param.encrypt_key.key_material, extra, dwrq->length);
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
+ else
+ sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sec->param.encrypt_key.key_disable = MTRUE;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * iwconfig mlanX key open
+ * iwconfig mlanX key restricted
+ * Do we want to just set the transmit key index ?
+ */
+ if (index < 0) {
+ PRINTM(MINFO, "*** iwconfig mlanX key on ***\n");
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ } else
+ sec->param.encrypt_key.key_index = index;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ switch (dwrq->flags & 0xf000) {
+ case IW_ENCODE_RESTRICTED:
+ /* iwconfig mlanX restricted key [1] */
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ break;
+ case IW_ENCODE_OPEN:
+ /* iwconfig mlanX key [2] open */
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ break;
+ case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
+ default:
+ /* iwconfig mlanX key [2] open restricted */
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u32 auth_mode;
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+
+ case MLAN_AUTH_MODE_AUTO:
+ dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED;
+ break;
+
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (!index)
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ else
+ sec->param.encrypt_key.key_index = index - 1;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(extra, 0, 16);
+ if (sec->param.encrypt_key.key_len) {
+ memcpy(extra, sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ dwrq->length = sec->param.encrypt_key.key_len;
+ dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else if (sec->param.encrypt_key.key_disable)
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ else
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+
+ dwrq->flags |= IW_ENCODE_NOKEY;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_rate_cfg_t rate_cfg;
+
+ ENTER();
+
+ if (vwrq->value == -1) {
+ rate_cfg.is_rate_auto = 1;
+ } else {
+ rate_cfg.is_rate_auto = 0;
+ rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate_cfg.rate = vwrq->value / 500000;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
+ MLAN_ACT_SET,
+ &rate_cfg)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_rate_cfg_t rate_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
+ MLAN_ACT_GET,
+ &rate_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (rate_cfg.is_rate_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ vwrq->value = rate_cfg.rate * 500000;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int rthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ rthr = MLAN_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int rthr, ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = rthr;
+ vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE)
+ || (vwrq->value > MLAN_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int fthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ fthr = MLAN_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, fthr;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = fthr;
+ vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE)
+ || (vwrq->value > MLAN_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+#if (WIRELESS_EXT >= 18)
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int copy_size = 0, ie_len;
+ t_u8 ie[MAX_IE_SIZE];
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie, &ie_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ copy_size = MIN(ie_len, dwrq->length);
+ memcpy(extra, ie, copy_size);
+ dwrq->length = copy_size;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ie_len = dwrq->length;
+ const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* extra + 2 to skip element id and length */
+ if (!memcmp((t_u8 *) (extra + 2), wps_oui, sizeof(wps_oui))) {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, (t_u8 *) extra, &ie_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+
+ ENTER();
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ pkey_material = (t_u8 *) (ext + 1);
+ sec->param.encrypt_key.key_len = ext->key_len;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) ext->addr.sa_data, ETH_ALEN);
+ /* Disable and Remove Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ PRINTM(MIOCTL,
+ "Remove key key_index=%d, dwrq->flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n",
+ key_index, dwrq->flags, sec->param.encrypt_key.mac_addr[0],
+ sec->param.encrypt_key.mac_addr[1],
+ sec->param.encrypt_key.mac_addr[2],
+ sec->param.encrypt_key.mac_addr[3],
+ sec->param.encrypt_key.mac_addr[4],
+ sec->param.encrypt_key.mac_addr[5]);
+ } else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
+ /* Set WEP key */
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else {
+ /* Set WPA key */
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ PRINTM(MIOCTL,
+ "set wpa key key_index=%d, key_len=%d key_flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n",
+ key_index, ext->key_len, sec->param.encrypt_key.key_flags,
+ sec->param.encrypt_key.mac_addr[0],
+ sec->param.encrypt_key.mac_addr[1],
+ sec->param.encrypt_key.mac_addr[2],
+ sec->param.encrypt_key.mac_addr[3],
+ sec->param.encrypt_key.mac_addr[4],
+ sec->param.encrypt_key.mac_addr[5]);
+ DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len);
+#define IW_ENCODE_ALG_SMS4 0x20
+ /* Set WAPI key */
+ if (ext->alg == IW_ENCODE_ALG_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
+ SEQ_MAX_SIZE);
+ memcpy(&sec->param.encrypt_key.pn[SEQ_MAX_SIZE],
+ (t_u8 *) ext->rx_seq, SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "WAPI PN", sec->param.encrypt_key.pn, PN_SIZE);
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_mlme(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *dwrq, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) mlme->addr.sa_data))
+ ret = -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 auth_mode = 0;
+ t_u32 encrypt_mode = 0;
+ ENTER();
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (vwrq->value & IW_AUTH_CIPHER_NONE)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ PRINTM(MINFO, "Auth mode LEAP!\n");
+ auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM:
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+#define IW_AUTH_WAPI_ENABLED 0x20
+ case IW_AUTH_WAPI_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
+ priv->wpa_version = vwrq->value;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
+ priv->key_mgmt = vwrq->value;
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 encrypt_mode = 0;
+ t_u32 auth_mode;
+ t_u32 wpa_enable;
+ ENTER();
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
+ ret = -EFAULT;
+ else {
+ if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
+ vwrq->value = IW_AUTH_CIPHER_WEP40;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
+ vwrq->value = IW_AUTH_CIPHER_WEP104;
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
+ ret = -EFAULT;
+ else {
+ if (auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
+ ret = -EFAULT;
+ else
+ vwrq->value = wpa_enable;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ vwrq->value = priv->wpa_version;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ vwrq->value = priv->key_mgmt;
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set PMKSA Cache
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_set_pmksa(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+#endif /* WE >= 18 */
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int i;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iw_range *range = (struct iw_range *) extra;
+ moal_802_11_rates rates;
+ mlan_chan_list *pchan_list = NULL;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (!(pchan_list = kmalloc(sizeof(mlan_chan_list), GFP_KERNEL))) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ memset(&rates, 0, sizeof(rates));
+ woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
+ range->num_bitrates = rates.num_of_rates;
+
+ for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
+ i++) {
+ range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+
+ memset(pchan_list, 0, sizeof(mlan_chan_list));
+
+ woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list);
+
+ range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long) pchan_list->cf[i].channel;
+ range->freq[i].m = (long) pchan_list->cf[i].freq * 100000;
+ range->freq[i].e = 1;
+ }
+ kfree(pchan_list);
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+ /*
+ * Set the qual, level and noise range values
+ */
+ /*
+ * need to put the right values here
+ */
+/** Maximum quality percentage */
+#define IW_MAX_QUAL_PERCENT 5
+/** Average quality percentage */
+#define IW_AVG_QUAL_PERCENT 3
+ range->max_qual.qual = IW_MAX_QUAL_PERCENT;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+
+ range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+
+ range->sensitivity = 0;
+
+ /*
+ * Setup the supported power level ranges
+ */
+ memset(range->txpower, 0, sizeof(range->txpower));
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ range->txpower[0] = bss_info.min_power_level;
+ range->txpower[1] = bss_info.max_power_level;
+ range->num_txpower = 2;
+ range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+
+ LEAVE();
+ return 0;
+}
+
+#ifdef MEF_CFG_RX_FILTER
+/**
+ * @brief Enable/disable Rx broadcast/multicast filter in non-HS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE: enable/disable
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_set_rxfilter(moal_private * priv, BOOLEAN enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_mef_cfg *mef_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ mef_cfg = &misc->param.mef_cfg;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_MEF_CFG;
+ req->action = MLAN_ACT_SET;
+
+ mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE);
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set priv command
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_priv(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ char *buf = NULL;
+ int power_mode = 0;
+ int band = 0;
+ char *pband = NULL;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ mlan_rate_cfg_t rate;
+ char *pdata;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ int len = 0;
+ ENTER();
+ if (!(buf = kmalloc(dwrq->length + 1, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(buf, 0, dwrq->length + 1);
+ if (copy_from_user(buf, dwrq->pointer, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "SIOCSIWPRIV requst = %s\n", buf);
+ if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) {
+ pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_rssi_low_threshold(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT,
+ &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_info.media_connected) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len =
+ sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
+ signal.bcn_rssi_avg) + 1;
+ } else {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+ } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate);
+ len =
+ sprintf(buf, "LinkSpeed %d\n",
+ (int) (rate.rate * 500000 / 1000000)) + 1;
+ } else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
+ len =
+ sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ priv->current_addr[0], priv->current_addr[1],
+ priv->current_addr[2], priv->current_addr[3],
+ priv->current_addr[4], priv->current_addr[5]) + 1;
+ } else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_powermode(priv, &power_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
+ } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ PRINTM(MIOCTL, "Set Active Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ PRINTM(MIOCTL, "Set Passive Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
+ pdata = buf + strlen("POWERMODE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_powermode(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
+ memset(country_code, 0, sizeof(country_code));
+ memcpy(country_code, buf + strlen("COUNTRY") + 1,
+ strlen(buf) - strlen("COUNTRY") - 1);
+ PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
+ if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) {
+ PRINTM(MIOCTL, "Set Combo Scan\n");
+ if (MLAN_STATUS_SUCCESS != woal_set_combo_scan(priv, buf, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "Band %d\n", band) + 1;
+ } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
+ pband = buf + strlen("SETBAND") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "START", strlen("START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_bg_scan(priv, buf, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
+ if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
+ if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MTRUE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MFALSE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ pdata = buf + strlen("RXFILTER-ADD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == 0) {
+ pdata = buf + strlen("RXFILTER-REMOVE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
+ pdata = buf + strlen("QOSINFO") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_qos_cfg(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
+ pdata = buf + strlen("SLEEPPD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
+ dwrq->length = (t_u16) len;
+ if (copy_to_user(dwrq->pointer, buf, dwrq->length)) {
+ ret = -EFAULT;
+ }
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Scan Network
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ moal_handle *handle = priv->phandle;
+#if WIRELESS_EXT >= 18
+ struct iw_scan_req *req;
+ struct iw_point *dwrq = (struct iw_point *) vwrq;
+#endif
+ mlan_802_11_ssid req_ssid;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+
+#if WIRELESS_EXT >= 18
+ if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
+ (dwrq->length == sizeof(struct iw_scan_req))) {
+ req = (struct iw_scan_req *) extra;
+
+ if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
+
+ req_ssid.ssid_len = req->essid_len;
+ memcpy(req_ssid.ssid, (t_u8 *) req->essid, req->essid_len);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+#endif
+ if (MLAN_STATUS_SUCCESS != woal_request_scan(priv, MOAL_NO_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#if WIRELESS_EXT >= 18
+ }
+#endif
+
+ if (priv->phandle->surprise_removed) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+#endif
+ int ret = 0;
+ t_u32 mode = 0;
+
+ ENTER();
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto setessid_ret;
+ }
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+#if WIRELESS_EXT > 20
+ req_ssid.ssid_len = dwrq->length;
+#else
+ req_ssid.ssid_len = dwrq->length - 1;
+#endif
+
+ /*
+ * Check if we asked for `any' or 'particular'
+ */
+ if (!dwrq->flags) {
+#ifdef REASSOCIATION
+ if (!req_ssid.ssid_len) {
+ memset(&priv->prev_ssid_bssid.ssid, 0x00, sizeof(mlan_802_11_ssid));
+ memset(&priv->prev_ssid_bssid.bssid, 0x00, MLAN_MAC_ADDR_LENGTH);
+ goto setessid_ret;
+ }
+#endif
+ /* Do normal SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else {
+ /* Set the SSID */
+ memcpy(req_ssid.ssid, extra,
+ MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
+ if (!req_ssid.ssid_len || (MFALSE == woal_ssid_valid(&req_ssid))) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+
+ PRINTM(MINFO, "Requested new SSID = %s\n", (char *) req_ssid.ssid);
+ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
+
+ if (dwrq->flags != 0xFFFF) {
+ if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+ }
+
+ }
+
+ /* disconnect before try to associate */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+
+ if (mode != IW_MODE_ADHOC) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv);
+
+ /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
+ MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+#endif /* REASSOCIATION */
+
+ setessid_ret:
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_bss_info bss_info;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_info.media_connected) {
+ dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
+ memcpy(extra, bss_info.ssid.ssid, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ if (bss_info.scan_table_idx)
+ dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
+ else
+ dwrq->flags = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ char *current_ev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+ unsigned int i;
+ unsigned int j;
+ mlan_scan_resp scan_resp;
+ mlan_bss_info bss_info;
+ BSSDescriptor_t *scan_table;
+ mlan_ds_get_signal rssi;
+ t_u16 buf_size = 16 + 256 * 2;
+ char *buf = NULL;
+ char *ptr;
+#if WIRELESS_EXT >= 18
+ t_u8 *praw_data;
+#endif
+ int beacon_size;
+ t_u8 *pbeacon;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+
+ ENTER();
+
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ LEAVE();
+ return -EAGAIN;
+ }
+
+ if (!(buf = kmalloc((buf_size), GFP_KERNEL))) {
+ PRINTM(MERROR, "Cannot allocate buffer!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
+ MOAL_IOCTL_WAIT,
+ &scan_resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ scan_table = (BSSDescriptor_t *) scan_resp.pscan_table;
+ if (dwrq->length)
+ end_buf = extra + dwrq->length;
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
+ }
+ PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
+ (int) scan_resp.num_in_scan_table);
+
+#if WIRELESS_EXT > 13
+ /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. The new
+ API using SIOCGIWSCAN is only limited by buffer size WE-14 -> WE-16 the
+ buffer is limited to IW_SCAN_MAX_DATA bytes which is 4096. */
+ for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+ PRINTM(MINFO, "i=%d break out: current_ev=%p end_buf=%p "
+ "MAX_SCAN_CELL_SIZE=%d\n",
+ i, current_ev, end_buf, (t_u32) MAX_SCAN_CELL_SIZE);
+ ret = -E2BIG;
+ break;
+ }
+ if (!scan_table[i].freq) {
+ PRINTM(MERROR, "Invalid channel number %d\n",
+ (int) scan_table[i].channel);
+ continue;
+ }
+ PRINTM(MINFO, "i=%d Ssid: %-32s\n", i, scan_table[i].ssid.ssid);
+
+ /* check ssid is valid or not, ex. hidden ssid will be filter out */
+ if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE) {
+ continue;
+ }
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &scan_table[i].mac_address, ETH_ALEN);
+
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add the ESSID */
+ iwe.u.data.length = scan_table[i].ssid.ssid_len;
+
+ if (iwe.u.data.length > 32) {
+ iwe.u.data.length = 32;
+ }
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
+ (t_s8 *) scan_table[i].ssid.ssid);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
+ iwe.u.mode = IW_MODE_ADHOC;
+ else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_AUTO;
+
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Frequency */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = (long) scan_table[i].freq * 100000;
+ iwe.u.freq.e = 1;
+ iwe.u.freq.flags = IW_FREQ_FIXED;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ memset(&iwe, 0, sizeof(iwe));
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
+ if (!bss_info.bcn_nf_last) {
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ iwe.u.qual.noise = bss_info.bcn_nf_last;
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
+ && bss_info.adhoc_state == ADHOC_STARTED) {
+ memset(&rssi, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &rssi)) {
+ ret = -EFAULT;
+ break;
+ }
+ iwe.u.qual.level = rssi.data_rssi_avg;
+ }
+ iwe.u.qual.qual =
+ woal_rssi_to_quality((t_s16) (iwe.u.qual.level - 0x100));
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (scan_table[i].privacy) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ }
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, NULL);
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ iwe.cmd = SIOCGIWRATE;
+
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
+ if (!scan_table[i].supported_rates[j]) {
+ break;
+ }
+
+ iwe.u.bitrate.value =
+ (scan_table[i].supported_rates[j] & 0x7f) * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val =
+ IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf,
+ &iwe, iwe.len);
+
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
+ && bss_info.adhoc_state == ADHOC_STARTED) {
+ iwe.u.bitrate.value = 22 * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val =
+ IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf,
+ &iwe, iwe.len);
+ }
+
+ /* Check if an event is added */
+ if ((unsigned int) (current_val - current_ev) >= IW_EV_PARAM_LEN)
+ current_ev = current_val;
+
+ /* Beacon Interval */
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "Beacon interval=%d", scan_table[i].beacon_period);
+
+ iwe.u.data.length = strlen(buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+
+ /* Parse and send the IEs */
+ pbeacon = scan_table[i].pbeacon_buf;
+ beacon_size = scan_table[i].beacon_buf_size;
+
+ /* Skip time stamp, beacon interval and capability */
+ if (pbeacon) {
+ pbeacon += sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+ beacon_size -= sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+
+ while ((unsigned int) beacon_size >= sizeof(IEEEtypes_Header_t)) {
+ element_id = (IEEEtypes_ElementId_e) (*(t_u8 *) pbeacon);
+ element_len = *((t_u8 *) pbeacon + 1);
+ if ((unsigned int) beacon_size <
+ (unsigned int) element_len + sizeof(IEEEtypes_Header_t)) {
+ PRINTM(MERROR,
+ "Get scan: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+
+ switch (element_id) {
+#if WIRELESS_EXT >= 18
+ case VENDOR_SPECIFIC_221:
+ case RSN_IE:
+ case WAPI_IE:
+ praw_data = (t_u8 *) pbeacon;
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ memcpy(buf, praw_data,
+ element_len + sizeof(IEEEtypes_Header_t));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length =
+ element_len + sizeof(IEEEtypes_Header_t);
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
+ buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+ break;
+#endif
+ default:
+ break;
+ }
+ pbeacon += element_len + sizeof(IEEEtypes_Header_t);
+ beacon_size -= element_len + sizeof(IEEEtypes_Header_t);
+ }
+ }
+#if WIRELESS_EXT > 14
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "band=");
+ memset(&iwe, 0, sizeof(iwe));
+ if (scan_table[i].bss_band == BAND_A)
+ ptr += sprintf(ptr, "a");
+ else
+ ptr += sprintf(ptr, "bg");
+ iwe.u.data.length = strlen(buf);
+ PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+ PRINTM(MINFO, "BUF: %s \n", buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+#endif
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ /*
+ * Check if we added any event
+ */
+ if ((unsigned int) (current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ dwrq->length = (current_ev - extra);
+ dwrq->flags = 0;
+#endif
+
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) woal_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler) woal_set_sens, /* SIOCSIWSENS */
+ (iw_handler) woal_get_sens, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler) woal_set_priv, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler) woal_set_wap, /* SIOCSIWAP */
+ (iw_handler) woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler) woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler) NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) woal_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) woal_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler) woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler) woal_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) woal_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_rate, /* SIOCSIWRATE */
+ (iw_handler) woal_get_rate, /* SIOCGIWRATE */
+ (iw_handler) woal_set_rts, /* SIOCSIWRTS */
+ (iw_handler) woal_get_rts, /* SIOCGIWRTS */
+ (iw_handler) woal_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) woal_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) woal_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) woal_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler) woal_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) woal_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) woal_set_power, /* SIOCSIWPOWER */
+ (iw_handler) woal_get_power, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler) woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+ (iw_handler) woal_set_pmksa, /* SIOCSIWPMKSA */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+#endif /* STA_SUPPORT */
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#if WIRELESS_EXT > 14
+
+/**
+ * @brief This function sends customized event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param str A pointer to event string
+ *
+ * @return N/A
+ */
+void
+woal_send_iwevcustom_event(moal_private * priv, t_s8 * str)
+{
+ union iwreq_data iwrq;
+ char buf[IW_CUSTOM_MAX];
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.pointer = buf;
+ iwrq.data.length = strlen(buf) + 1;
+
+ /* Send Event to upper layer */
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
+ PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
+
+ LEAVE();
+ return;
+}
+#endif
+
+#if WIRELESS_EXT >= 18
+/**
+ * @brief This function sends mic error event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event MIC MERROR EVENT.
+ *
+ * @return N/A
+ */
+void
+woal_send_mic_error_event(moal_private * priv, t_u32 event)
+{
+ union iwreq_data iwrq;
+ struct iw_michaelmicfailure mic;
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(iwrq));
+ memset(&mic, 0, sizeof(mic));
+ if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
+ mic.flags = IW_MICFAILURE_PAIRWISE;
+ else
+ mic.flags = IW_MICFAILURE_GROUP;
+ iwrq.data.pointer = &mic;
+ iwrq.data.length = sizeof(mic);
+
+ wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
+ (char *) &mic);
+
+ LEAVE();
+ return;
+}
+#endif
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set Radio On/OFF
+ *
+ * @param priv A pointer to moal_private structure
+ * @param option Radio Option
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_radio(moal_private * priv, t_u8 option)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ ENTER();
+ if ((option != 0) && (option != 1)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) req->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = option;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** wlan_handler_def */
+struct iw_handler_def woal_handler_def = {
+ num_standard:sizeof(woal_handler) / sizeof(iw_handler),
+ num_private:sizeof(woal_private_handler) / sizeof(iw_handler),
+ num_private_args:sizeof(woal_private_args) / sizeof(struct iw_priv_args),
+ standard:(iw_handler *) woal_handler,
+ private:(iw_handler *) woal_private_handler,
+ private_args:(struct iw_priv_args *) woal_private_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats:woal_get_wireless_stats,
+#endif
+};
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+woal_get_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u16 wait_option = MOAL_NO_WAIT;
+
+ ENTER();
+
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (write_can_lock(&dev_base_lock)
+ && (!in_atomic() || current->exit_state))
+ wait_option = MOAL_WSTATS_WAIT;
+
+ priv->w_stats.status = woal_get_mode(priv, wait_option);
+ priv->w_stats.discard.retries = priv->stats.tx_errors;
+ priv->w_stats.qual.qual = 0;
+
+ /* Send RSSI command to get beacon RSSI/NF, valid only if associated */
+ if (priv->media_connected == MTRUE) {
+ woal_get_signal_info(priv, wait_option, NULL);
+ priv->w_stats.qual.qual = woal_rssi_to_quality((t_s16)
+ (priv->w_stats.qual.
+ level - 0x100));
+ }
+#if WIRELESS_EXT > 18
+ priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
+#else
+ priv->w_stats.qual.updated |= 7;
+#endif
+ if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
+ priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+
+ PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual);
+ PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
+ PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
+ priv->w_stats.discard.code = 0;
+ woal_get_stats_info(priv, wait_option, NULL);
+
+ LEAVE();
+ return &priv->w_stats;
+}
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.h b/drivers/net/wireless/sd8797/mlinux/moal_wext.h
new file mode 100644
index 000000000000..dfafff866b96
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.h
@@ -0,0 +1,115 @@
+/** @file moal_wext.h
+ *
+ * @brief This file contains definition for wireless extension IOCTL call.
+ *
+ * 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/21/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_WEXT_H_
+#define _WOAL_WEXT_H_
+
+/** Custom event : AdHoc link sensed */
+#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED"
+/** Custom event : AdHoc link lost */
+#define CUS_EVT_ADHOC_LINK_LOST "EVENT=ADHOC_LINK_LOST"
+/** Custom event : MIC failure, unicast */
+#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast "
+/** Custom event : MIC failure, multicast */
+#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast "
+/** Custom event : Beacon RSSI low */
+#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW"
+/** Custom event : Beacon SNR low */
+#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW"
+/** Custom event : Beacon RSSI high */
+#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH"
+/** Custom event : Beacon SNR high */
+#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH"
+/** Custom event : Max fail */
+#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL"
+/** Custom event : Data RSSI low */
+#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW"
+/** Custom event : Data SNR low */
+#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW"
+/** Custom event : Data RSSI high */
+#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH"
+/** Custom event : Data SNR high */
+#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH"
+/** Custom event : Link Quality */
+#define CUS_EVT_LINK_QUALITY "EVENT=LINK_QUALITY"
+/** Custom event : Port Release */
+#define CUS_EVT_PORT_RELEASE "EVENT=PORT_RELEASE"
+/** Custom event : Pre-Beacon Lost */
+#define CUS_EVT_PRE_BEACON_LOST "EVENT=PRE_BEACON_LOST"
+
+/** Custom event : Deep Sleep awake */
+#define CUS_EVT_DEEP_SLEEP_AWAKE "EVENT=DS_AWAKE"
+
+/** Custom event : Host Sleep activated */
+#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED "
+/** Custom event : Host Sleep deactivated */
+#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED "
+/** Custom event : Host Sleep wakeup */
+#define CUS_EVT_HS_WAKEUP "HS_WAKEUP"
+
+/** Custom event : WEP ICV error */
+#define CUS_EVT_WEP_ICV_ERR "EVENT=WEP_ICV_ERR"
+
+/** Custom event : Channel Switch Announcment */
+#define CUS_EVT_CHANNEL_SWITCH_ANN "EVENT=CHANNEL_SWITCH_ANN"
+
+/** Custom event : BW changed */
+#define CUS_EVT_BW_CHANGED "EVENT=BW_CHANGED"
+/** Custom event : OBSS scan parameter */
+#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM"
+/** Custom indiciation message sent to the application layer for WMM changes */
+#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication"
+
+#ifdef UAP_SUPPORT
+#ifdef UAP_WEXT
+/** Custom event : STA connected */
+#define CUS_EVT_STA_CONNECTED "EVENT=STA_CONNECTED"
+/** Custom event : STA disconnected */
+#define CUS_EVT_STA_DISCONNECTED "EVENT=STA_DISCONNECTED"
+#endif
+#endif
+/** NF value for default scan */
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((i), (c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((i), (c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((i), (c), (v), (e), (w), (l))
+#else
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((c), (v), (e), (w), (l))
+#endif
+
+extern struct iw_handler_def woal_handler_def;
+struct iw_statistics *woal_get_wireless_stats(struct net_device *dev);
+#endif /* _WOAL_WEXT_H_ */
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index e392f4dc77de..857deb8faa0a 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -885,6 +885,9 @@ static int bq27x00_battery_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+ cancel_delayed_work_sync(&di->work);
+ cancel_delayed_work_sync(&di->external_power_changed_work);
+
if (di->chip == BQ27510) {
ret = bq27x00_write(di, BQ27510_CNTL,
BQ27510_CNTL_SET_SLEEP, false);
@@ -920,6 +923,9 @@ static int bq27x00_battery_resume(struct device *dev)
return ret;
}
}
+
+ schedule_delayed_work(&di->work, HZ);
+
return 0;
}
diff --git a/drivers/power/max17048_battery.c b/drivers/power/max17048_battery.c
index e43390984522..c65855f72dba 100644
--- a/drivers/power/max17048_battery.c
+++ b/drivers/power/max17048_battery.c
@@ -177,7 +177,7 @@ static void max17048_get_vcell(struct i2c_client *client)
if (vcell < 0)
dev_err(&client->dev, "%s: err %d\n", __func__, vcell);
else
- chip->vcell = (uint16_t)vcell;
+ chip->vcell = (uint16_t)(((vcell >> 4) * 125) / 100);
}
static void max17048_get_soc(struct i2c_client *client)
@@ -276,13 +276,18 @@ static int max17048_write_rcomp_seg(struct i2c_client *client,
{
uint8_t rs1, rs2;
int ret;
+ uint8_t rcomp_seg_table[16];
rs2 = rcomp_seg | 0x00FF;
rs1 = rcomp_seg >> 8;
- uint8_t rcomp_seg_table[16] = { rs1, rs2, rs1, rs2,
- rs1, rs2, rs1, rs2,
- rs1, rs2, rs1, rs2,
- rs1, rs2, rs1, rs2};
+
+ rcomp_seg_table[0] = rcomp_seg_table[2] = rcomp_seg_table[4] =
+ rcomp_seg_table[6] = rcomp_seg_table[8] = rcomp_seg_table[10] =
+ rcomp_seg_table[12] = rcomp_seg_table[14] = rs1;
+
+ rcomp_seg_table[1] = rcomp_seg_table[3] = rcomp_seg_table[5] =
+ rcomp_seg_table[7] = rcomp_seg_table[9] = rcomp_seg_table[11] =
+ rcomp_seg_table[13] = rcomp_seg_table[15] = rs2;
ret = i2c_smbus_write_i2c_block_data(client, MAX17048_RCOMPSEG1,
16, (uint8_t *)rcomp_seg_table);
@@ -562,14 +567,30 @@ static int max17048_suspend(struct i2c_client *client,
pm_message_t state)
{
struct max17048_chip *chip = i2c_get_clientdata(client);
+ int ret;
cancel_delayed_work(&chip->work);
+
+ ret = max17048_write_word(client, MAX17048_HIBRT, 0xffff);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed in entering hibernate mode\n");
+ return ret;
+ }
+
return 0;
}
static int max17048_resume(struct i2c_client *client)
{
struct max17048_chip *chip = i2c_get_clientdata(client);
+ int ret;
+ struct max17048_battery_model *mdata = chip->model_data;
+
+ ret = max17048_write_word(client, MAX17048_HIBRT, mdata->hibernate);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed in exiting hibernate mode\n");
+ return ret;
+ }
schedule_delayed_work(&chip->work, MAX17048_DELAY);
return 0;
diff --git a/drivers/power/smb349-charger.c b/drivers/power/smb349-charger.c
index 9ee8b288d225..58778409b6ba 100644
--- a/drivers/power/smb349-charger.c
+++ b/drivers/power/smb349-charger.c
@@ -170,17 +170,28 @@ static int smb349_configure_otg(struct i2c_client *client, int enable)
}
if (enable) {
- /* Configure PGOOD to be active low */
- ret = smb349_read(client, SMB349_SYSOK_USB3);
+ /* Configure PGOOD to be active low if no 5V on VBUS */
+ ret = smb349_read(client, SMB349_STS_REG_C);
if (ret < 0) {
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
goto error;
}
- ret = smb349_write(client, SMB349_SYSOK_USB3, (ret & (~(1))));
- if (ret < 0) {
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
- goto error;
+ if (!(ret & 0x01)) {
+ ret = smb349_read(client, SMB349_SYSOK_USB3);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n",
+ __func__, ret);
+ goto error;
+ }
+
+ ret = smb349_write(client, SMB349_SYSOK_USB3,
+ (ret & (~(1))));
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n",
+ __func__, ret);
+ goto error;
+ }
}
/* Enable OTG */
@@ -274,9 +285,14 @@ error:
int update_charger_status(void)
{
- struct i2c_client *client = charger->client;
+ struct i2c_client *client;
int ret, val;
+ if (!charger)
+ return -ENODEV;
+ else
+ client = charger->client;
+
val = smb349_read(client, SMB349_STS_REG_D);
if (val < 0) {
dev_err(&client->dev, "%s(): Failed in reading register"
@@ -383,6 +399,7 @@ static int smb349_enable_charging(struct regulator_dev *rdev,
"charger..\n", __func__);
return ret;
}
+ charger->chrg_type = NONE;
} else {
ret = smb349_read(client, SMB349_STS_REG_D);
if (ret < 0) {
@@ -420,7 +437,7 @@ static int __devinit smb349_probe(struct i2c_client *client,
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct smb349_charger_platform_data *pdata;
- int ret, irq_num;
+ int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO;
@@ -444,7 +461,7 @@ static int __devinit smb349_probe(struct i2c_client *client,
dev_err(&client->dev, "%s() No Battery present, exiting..\n",
__func__);
ret = -ENODEV;
- goto error;
+ goto regulator_error;
}
charger->reg_desc.name = "vbus_charger";
@@ -480,7 +497,7 @@ static int __devinit smb349_probe(struct i2c_client *client,
dev_err(&client->dev, "failed to register %s\n",
charger->reg_desc.name);
ret = PTR_ERR(charger->rdev);
- goto error;
+ goto regulator_error;
}
/* disable OTG */
@@ -520,7 +537,10 @@ static int __devinit smb349_probe(struct i2c_client *client,
return 0;
error:
+ regulator_unregister(charger->rdev);
+regulator_error:
kfree(charger);
+ charger = NULL;
return ret;
}
@@ -528,7 +548,7 @@ static int __devexit smb349_remove(struct i2c_client *client)
{
struct smb349_charger *charger = i2c_get_clientdata(client);
- free_irq(gpio_to_irq(client->irq), charger);
+ regulator_unregister(charger->rdev);
kfree(charger);
return 0;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d3cb8e6ff099..67093e3f1cd7 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -117,6 +117,15 @@ config REGULATOR_MAX8952
via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS
modes ranging from 0.77V to 1.40V by 0.01V steps.
+config REGULATOR_MAX8973
+ tristate "Maxim MAX8973 Power Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports MAX8973 voltage regulator chip.
+ The MAX8973 high-efficiency, three-phase, DC-DC step-down switching
+ regulator delivers up to 9A of output current.
+
config REGULATOR_MAX8997
tristate "Maxim 8997/8966 regulator"
depends on MFD_MAX8997
@@ -345,6 +354,16 @@ config REGULATOR_TPS62360
high-frequency synchronous step down dc-dc converter optimized
for battery-powered portable applications.
+config REGULATOR_TPS6238X0
+ tristate "TI TPS623850/TPS623860/TPS623870 Power Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports TPS6238X0 voltage regulator chip. This
+ regulator is meant for processor core supply. This chip is
+ high-frequency synchronous step down dc-dc converter optimized
+ for battery-powered portable applications.
+
config REGULATOR_AAT2870
tristate "AnalogicTech AAT2870 Regulators"
depends on MFD_AAT2870_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4fc5c3f275ab..7642d39fb8d3 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
+obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX8907C) += max8907c-regulator.o
@@ -52,6 +53,7 @@ obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6238X0) += tps6238x0-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 1b7d64118e4d..cbe36b93639b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -91,6 +91,8 @@ struct regulator {
static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator_dev *rdev);
+static int _regulator_enable(struct regulator_dev *rdev);
+static int _regulator_get_enable_time(struct regulator_dev *rdev);
static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -358,7 +360,65 @@ static ssize_t regulator_state_show(struct device *dev,
return ret;
}
-static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+
+static ssize_t regulator_state_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ int ret;
+ bool enabled;
+
+ if ((*buf == 'E') || (*buf == 'e'))
+ enabled = true;
+ else if ((*buf == 'D') || (*buf == 'd'))
+ enabled = false;
+ else
+ return -EINVAL;
+
+ if ((_regulator_is_enabled(rdev) && enabled) ||
+ (!_regulator_is_enabled(rdev) && !enabled))
+ return count;
+
+ mutex_lock(&rdev->mutex);
+ if (enabled) {
+ int delay = 0;
+ if (!rdev->desc->ops->enable) {
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = _regulator_get_enable_time(rdev);
+ if (ret >= 0)
+ delay = ret;
+ ret = rdev->desc->ops->enable(rdev);
+ if (ret < 0) {
+ rdev_warn(rdev, "enable() failed: %d\n", ret);
+ goto end;
+ }
+ if (delay >= 1000) {
+ mdelay(delay / 1000);
+ udelay(delay % 1000);
+ } else if (delay) {
+ udelay(delay);
+ }
+ } else {
+ if (!rdev->desc->ops->disable) {
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = rdev->desc->ops->disable(rdev);
+ if (ret < 0) {
+ rdev_warn(rdev, "disable() failed: %d\n", ret);
+ goto end;
+ }
+ }
+
+end:
+ mutex_unlock(&rdev->mutex);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+static DEVICE_ATTR(state, 0644, regulator_state_show, regulator_state_set);
static ssize_t regulator_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
diff --git a/drivers/regulator/max77663-regulator.c b/drivers/regulator/max77663-regulator.c
index dca8ece4c433..55d2526b4490 100644
--- a/drivers/regulator/max77663-regulator.c
+++ b/drivers/regulator/max77663-regulator.c
@@ -280,7 +280,7 @@ static int max77663_regulator_set_fps(struct max77663_regulator *reg)
fps_mask |= FPS_PD_PERIOD_MASK;
}
- if (fps_val)
+ if (fps_val || fps_mask)
ret = max77663_regulator_cache_write(reg,
reg->regs[FPS_REG].addr, fps_mask,
fps_val, &reg->regs[FPS_REG].val);
@@ -704,15 +704,13 @@ skip_init_apply:
val |= (SD_SR_100 << SD_SR_SHIFT);
}
- if (pdata->flags & SD_FORCED_PWM_MODE) {
- mask |= SD_FPWM_MASK;
+ mask |= SD_FPWM_MASK;
+ if (pdata->flags & SD_FORCED_PWM_MODE)
val |= SD_FPWM_MASK;
- }
- if (pdata->flags & SD_FSRADE_DISABLE) {
- mask |= SD_FSRADE_MASK;
+ mask |= SD_FSRADE_MASK;
+ if (pdata->flags & SD_FSRADE_DISABLE)
val |= SD_FSRADE_MASK;
- }
ret = max77663_regulator_cache_write(reg,
reg->regs[CFG_REG].addr, mask, val,
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
new file mode 100644
index 000000000000..8d87970a1b31
--- /dev/null
+++ b/drivers/regulator/max8973-regulator.c
@@ -0,0 +1,606 @@
+/*
+ * max8973-regulator.c -- Maxim max8973
+ *
+ * Regulator driver for MAXIM 8973 DC-DC step-down switching regulator.
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/max8973-regulator.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+/* Register definitions */
+#define MAX8973_VOUT 0x0
+#define MAX8973_VOUT_DVS 0x1
+#define MAX8973_CONTROL1 0x2
+#define MAX8973_CONTROL2 0x3
+#define MAX8973_CHIPID1 0x4
+#define MAX8973_CHIPID2 0x5
+
+#define MAX8973_MAX_VOUT_REG 2
+
+/* MAX8973_VOUT */
+#define MAX8973_VOUT_ENABLE BIT(7)
+#define MAX8973_VOUT_MASK 0x7F
+
+/* MAX8973_VOUT_DVS */
+#define MAX8973_DVS_VOUT_MASK 0x7F
+
+/* MAX8973_CONTROL1 */
+#define MAX8973_SNS_ENABLE BIT(7)
+#define MAX8973_FPWM_EN_M BIT(6)
+#define MAX8973_NFSR_ENABLE BIT(5)
+#define MAX8973_AD_ENABLE BIT(4)
+#define MAX8973_BIAS_ENABLE BIT(3)
+#define MAX8973_FREQSHIFT_9PER BIT(2)
+
+#define MAX8973_RAMP_12mV_PER_US 0x0
+#define MAX8973_RAMP_25mV_PER_US 0x1
+#define MAX8973_RAMP_50mV_PER_US 0x2
+#define MAX8973_RAMP_200mV_PER_US 0x3
+
+/* MAX8973_CONTROL2 */
+#define MAX8973_WDTMR_ENABLE BIT(6)
+#define MAX8973_DISCH_ENBABLE BIT(5)
+#define MAX8973_FT_ENABLE BIT(4)
+
+#define MAX8973_CKKADV_TRIP_DISABLE 0xC
+#define MAX8973_CKKADV_TRIP_75mV_PER_US 0x0
+#define MAX8973_CKKADV_TRIP_150mV_PER_US 0x4
+#define MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8
+
+#define MAX8973_INDUCTOR_MIN_30_PER 0x0
+#define MAX8973_INDUCTOR_NOMINAL 0x1
+#define MAX8973_INDUCTOR_PLUS_30_PER 0x2
+#define MAX8973_INDUCTOR_PLUS_60_PER 0x3
+
+#define MAX8973_MIN_VOLATGE 606250
+#define MAX8973_MAX_VOLATGE 1400000
+#define MAX8973_VOLATGE_STEP 6250
+#define MAX8973_BUCK_N_VOLTAGE \
+ (((MAX8973_MAX_VOLATGE - MAX8973_MIN_VOLATGE) / MAX8973_VOLATGE_STEP) \
+ + 1)
+
+/* Maxim 8973 chip information */
+struct max8973_chip {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ bool enable_external_control;
+ int dvs_gpio;
+ int lru_index[MAX8973_MAX_VOUT_REG];
+ int curr_vout_val[MAX8973_MAX_VOUT_REG];
+ int curr_vout_reg;
+ int curr_gpio_val;
+ int change_uv_per_us;
+ bool valid_dvs_gpio;
+};
+
+/*
+ * find_voltage_set_register: Find new voltage configuration register (VOUT).
+ * The finding of the new VOUT register will be based on the LRU mechanism.
+ * Each VOUT register will have different voltage configured . This
+ * Function will look if any of the VOUT register have requested voltage set
+ * or not.
+ * - If it is already there then it will make that register as most
+ * recently used and return as found so that caller need not to set
+ * the VOUT register but need to set the proper gpios to select this
+ * VOUT register.
+ * - If requested voltage is not found then it will use the least
+ * recently mechanism to get new VOUT register for new configuration
+ * and will return not_found so that caller need to set new VOUT
+ * register and then gpios (both).
+ */
+static bool find_voltage_set_register(struct max8973_chip *tps,
+ int req_vsel, int *vout_reg, int *gpio_val)
+{
+ int i;
+ bool found = false;
+ int new_vout_reg = tps->lru_index[MAX8973_MAX_VOUT_REG - 1];
+ int found_index = MAX8973_MAX_VOUT_REG - 1;
+
+ for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i) {
+ if (tps->curr_vout_val[tps->lru_index[i]] == req_vsel) {
+ new_vout_reg = tps->lru_index[i];
+ found_index = i;
+ found = true;
+ goto update_lru_index;
+ }
+ }
+
+update_lru_index:
+ for (i = found_index; i > 0; i--)
+ tps->lru_index[i] = tps->lru_index[i - 1];
+
+ tps->lru_index[0] = new_vout_reg;
+ *gpio_val = new_vout_reg;
+ *vout_reg = MAX8973_VOUT + new_vout_reg;
+ return found;
+}
+
+static int max8973_dcdc_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(max->regmap, max->curr_vout_reg, &data);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d read failed with err %d\n",
+ __func__, max->curr_vout_reg, ret);
+ return ret;
+ }
+ return data & MAX8973_VOUT_MASK;
+}
+
+static int max8973_dcdc_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int vsel;
+ int ret;
+ bool found = false;
+ int vout_reg = max->curr_vout_reg;
+ int gpio_val = max->curr_gpio_val;
+
+ if ((max_uV < min_uV) || (max_uV < MAX8973_MIN_VOLATGE) ||
+ (min_uV > MAX8973_MAX_VOLATGE))
+ return -EINVAL;
+
+ vsel = DIV_ROUND_UP(min_uV - MAX8973_MIN_VOLATGE, MAX8973_VOLATGE_STEP);
+ if (selector)
+ *selector = (vsel & MAX8973_VOUT_MASK);
+
+ /*
+ * If gpios are available to select the VOUT register then least
+ * recently used register for new configuration.
+ */
+ if (max->valid_dvs_gpio)
+ found = find_voltage_set_register(max, vsel,
+ &vout_reg, &gpio_val);
+
+ if (!found) {
+ ret = regmap_update_bits(max->regmap, vout_reg,
+ MAX8973_VOUT_MASK, vsel);
+ if (ret < 0) {
+ dev_err(max->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, vout_reg, ret);
+ return ret;
+ }
+ max->curr_vout_reg = vout_reg;
+ max->curr_vout_val[gpio_val] = vsel;
+ }
+
+ /* Select proper VOUT register vio gpios */
+ if (max->valid_dvs_gpio) {
+ gpio_set_value_cansleep(max->dvs_gpio, gpio_val & 0x1);
+ max->curr_gpio_val = gpio_val;
+ }
+ return 0;
+}
+
+static int max8973_dcdc_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector >= MAX8973_BUCK_N_VOLTAGE)
+ return -EINVAL;
+
+ return MAX8973_MIN_VOLATGE + selector * MAX8973_VOLATGE_STEP;
+}
+
+static int max8973_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+
+ old_uV = max8973_dcdc_list_voltage(rdev, old_selector);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = max8973_dcdc_list_voltage(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV), max->change_uv_per_us);
+}
+static int max8973_dcdc_enable(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (max->enable_external_control)
+ return 0;
+
+ ret = regmap_update_bits(max->regmap, MAX8973_VOUT,
+ MAX8973_VOUT_ENABLE, MAX8973_VOUT_ENABLE);
+ if (ret < 0)
+ dev_err(max->dev, "%s(): register %d update failed with err %d",
+ __func__, MAX8973_VOUT, ret);
+ return ret;
+}
+
+static int max8973_dcdc_disable(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret = 0;
+
+ if (max->enable_external_control)
+ return 0;
+
+ ret = regmap_update_bits(max->regmap, MAX8973_VOUT,
+ MAX8973_VOUT_ENABLE, 0);
+ if (ret < 0)
+ dev_err(max->dev, "%s(): register %d update failed with err %d",
+ __func__, MAX8973_VOUT, ret);
+ return ret;
+}
+
+static int max8973_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret;
+ unsigned int data;
+
+ if (max->enable_external_control)
+ return 1;
+
+ ret = regmap_read(max->regmap, MAX8973_VOUT, &data);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d read failed with err %d",
+ __func__, max->curr_vout_reg, ret);
+ return ret;
+ }
+
+ return !!(data & MAX8973_VOUT_ENABLE);
+}
+
+static int max8973_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret;
+ int pwm;
+
+ /* Enable force PWM mode in FAST mode only. */
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ pwm = MAX8973_FPWM_EN_M;
+ break;
+
+ case REGULATOR_MODE_NORMAL:
+ pwm = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1,
+ MAX8973_FPWM_EN_M, pwm);
+ if (ret < 0)
+ dev_err(max->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, MAX8973_CONTROL1, ret);
+ return ret;
+}
+
+static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(max->regmap, MAX8973_CONTROL1, &data);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d read failed with err %d\n",
+ __func__, MAX8973_CONTROL1, ret);
+ return ret;
+ }
+ return (data & MAX8973_FPWM_EN_M) ?
+ REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops max8973_dcdc_ops = {
+ .get_voltage_sel = max8973_dcdc_get_voltage_sel,
+ .set_voltage = max8973_dcdc_set_voltage,
+ .list_voltage = max8973_dcdc_list_voltage,
+ .set_voltage_time_sel = max8973_dcdc_set_voltage_time_sel,
+ .enable = max8973_dcdc_enable,
+ .disable = max8973_dcdc_disable,
+ .is_enabled = max8973_dcdc_is_enabled,
+ .set_mode = max8973_dcdc_set_mode,
+ .get_mode = max8973_dcdc_get_mode,
+};
+
+static int __devinit max8973_init_dcdc(struct max8973_chip *max,
+ struct max8973_regulator_platform_data *pdata)
+{
+ int ret;
+ uint8_t control1 = 0;
+ uint8_t control2 = 0;
+
+ if (pdata->control_flags & MAX8973_CONTROL_REMOTE_SENSE_ENABLE)
+ control1 |= MAX8973_SNS_ENABLE;
+
+ if (!(pdata->control_flags & MAX8973_CONTROL_FALLING_SLEW_RATE_ENABLE))
+ control1 |= MAX8973_NFSR_ENABLE;
+
+ if (pdata->control_flags & MAX8973_CONTROL_OUTPUT_ACTIVE_DISCH_ENABLE)
+ control1 |= MAX8973_AD_ENABLE;
+
+ if (pdata->control_flags & MAX8973_CONTROL_BIAS_ENABLE)
+ control1 |= MAX8973_BIAS_ENABLE;
+
+ if (pdata->control_flags & MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE)
+ control1 |= MAX8973_FREQSHIFT_9PER;
+
+ switch (pdata->control_flags & MAX8973_CONTROL_SLEW_RATE_200MV_PER_US) {
+ case MAX8973_CONTROL_SLEW_RATE_12_5mV_PER_US:
+ control1 = MAX8973_RAMP_12mV_PER_US;
+ max->change_uv_per_us = 12500;
+ break;
+
+ case MAX8973_CONTROL_SLEW_RATE_25mV_PER_US:
+ control1 = MAX8973_RAMP_25mV_PER_US;
+ max->change_uv_per_us = 25000;
+ break;
+
+ case MAX8973_CONTROL_SLEW_RATE_50mV_PER_US:
+ control1 = MAX8973_RAMP_50mV_PER_US;
+ max->change_uv_per_us = 50000;
+ break;
+
+ case MAX8973_CONTROL_SLEW_RATE_200MV_PER_US:
+ control1 = MAX8973_RAMP_200mV_PER_US;
+ max->change_uv_per_us = 200000;
+ break;
+ }
+
+ if (!(pdata->control_flags & MAX8973_CONTROL_PULL_DOWN_ENABLE))
+ control2 |= MAX8973_DISCH_ENBABLE;
+
+ switch (pdata->control_flags &
+ MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US) {
+ case MAX8973_CONTROL_CLKADV_TRIP_DISABLED:
+ control2 |= MAX8973_CKKADV_TRIP_DISABLE;
+ break;
+
+ case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US:
+ control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US;
+ break;
+
+ case MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US:
+ control2 |= MAX8973_CKKADV_TRIP_150mV_PER_US;
+ break;
+
+ case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US_HIST_DIS:
+ control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS;
+ break;
+ }
+
+ switch (pdata->control_flags &
+ MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER) {
+ case MAX8973_CONTROL_INDUCTOR_VALUE_NOMINAL:
+ control2 |= MAX8973_INDUCTOR_NOMINAL;
+ break;
+
+ case MAX8973_CONTROL_INDUCTOR_VALUE_MINUS_30_PER:
+ control2 |= MAX8973_INDUCTOR_MIN_30_PER;
+ break;
+
+ case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_30_PER:
+ control2 |= MAX8973_INDUCTOR_PLUS_30_PER;
+ break;
+
+ case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER:
+ control2 |= MAX8973_INDUCTOR_PLUS_60_PER;
+ break;
+ }
+
+ ret = regmap_write(max->regmap, MAX8973_CONTROL1, control1);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d write failed with err %d",
+ __func__, MAX8973_CONTROL1, ret);
+ return ret;
+ }
+
+ ret = regmap_write(max->regmap, MAX8973_CONTROL2, control2);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d write failed with err %d",
+ __func__, MAX8973_CONTROL2, ret);
+ return ret;
+ }
+
+ /* If external control is enabled then disable EN bit */
+ if (max->enable_external_control) {
+ ret = regmap_update_bits(max->regmap, MAX8973_VOUT,
+ MAX8973_VOUT_ENABLE, 0);
+ if (ret < 0)
+ dev_err(max->dev, "%s(): register %d update failed with err %d",
+ __func__, MAX8973_VOUT, ret);
+ }
+ return ret;
+}
+
+static const struct regmap_config max8973_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX8973_CHIPID2,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit max8973_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max8973_regulator_platform_data *pdata;
+ struct regulator_dev *rdev;
+ struct max8973_chip *max;
+ int ret;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "%s(): No Platform data", __func__);
+ return -EIO;
+ }
+
+ max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL);
+ if (!max) {
+ dev_err(&client->dev, "%s(): Memory allocation failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ max->dev = &client->dev;
+
+ max->desc.name = id->name;
+ max->desc.id = 0;
+ max->desc.ops = &max8973_dcdc_ops;
+ max->desc.type = REGULATOR_VOLTAGE;
+ max->desc.owner = THIS_MODULE;
+ max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config);
+ if (IS_ERR(max->regmap)) {
+ ret = PTR_ERR(max->regmap);
+ dev_err(&client->dev,
+ "%s(): regmap allocation failed with err %d\n",
+ __func__, ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, max);
+
+ max->enable_external_control = pdata->enable_ext_control;
+ max->dvs_gpio = pdata->dvs_gpio;
+ max->curr_gpio_val = pdata->dvs_def_state;
+ max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state;
+ max->lru_index[0] = max->curr_vout_reg;
+ max->valid_dvs_gpio = false;
+
+ if (gpio_is_valid(max->dvs_gpio)) {
+ int gpio_flags;
+ int i;
+
+ gpio_flags = (pdata->dvs_def_state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(max->dvs_gpio,
+ gpio_flags, "max8973-dvs");
+ if (ret) {
+ dev_err(&client->dev,
+ "%s(): Could not obtain dvs GPIO %d: %d\n",
+ __func__, max->dvs_gpio, ret);
+ return ret;
+ }
+ max->valid_dvs_gpio = true;
+
+ /*
+ * Initialize the lru index with vout_reg id
+ * The index 0 will be most recently used and
+ * set with the max->curr_vout_reg */
+ for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i)
+ max->lru_index[i] = i;
+ max->lru_index[0] = max->curr_vout_reg;
+ max->lru_index[max->curr_vout_reg] = 0;
+ }
+
+ ret = max8973_init_dcdc(max, pdata);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): Init failed with err = %d\n",
+ __func__, ret);
+ goto err_init;
+ }
+
+ /* Register the regulators */
+ rdev = regulator_register(&max->desc, &client->dev,
+ pdata->reg_init_data, max);
+ if (IS_ERR(rdev)) {
+ dev_err(max->dev,
+ "%s(): regulator register failed with err %s\n",
+ __func__, id->name);
+ ret = PTR_ERR(rdev);
+ goto err_init;
+ }
+
+ max->rdev = rdev;
+ return 0;
+
+err_init:
+ if (gpio_is_valid(max->dvs_gpio))
+ gpio_free(max->dvs_gpio);
+ return ret;
+}
+
+/**
+ * max8973_remove - max8973 driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister TPS driver as an i2c client device driver
+ */
+static int __devexit max8973_remove(struct i2c_client *client)
+{
+ struct max8973_chip *max = i2c_get_clientdata(client);
+
+ if (gpio_is_valid(max->dvs_gpio))
+ gpio_free(max->dvs_gpio);
+
+ regulator_unregister(max->rdev);
+ return 0;
+}
+
+static const struct i2c_device_id max8973_id[] = {
+ {.name = "max8973",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, max8973_id);
+
+static struct i2c_driver max8973_i2c_driver = {
+ .driver = {
+ .name = "max8973",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8973_probe,
+ .remove = __devexit_p(max8973_remove),
+ .id_table = max8973_id,
+};
+
+static int __init max8973_init(void)
+{
+ return i2c_add_driver(&max8973_i2c_driver);
+}
+subsys_initcall(max8973_init);
+
+static void __exit max8973_cleanup(void)
+{
+ i2c_del_driver(&max8973_i2c_driver);
+}
+module_exit(max8973_cleanup);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("MAX8973 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps6238x0-regulator.c b/drivers/regulator/tps6238x0-regulator.c
new file mode 100644
index 000000000000..611b9425a263
--- /dev/null
+++ b/drivers/regulator/tps6238x0-regulator.c
@@ -0,0 +1,470 @@
+/*
+ * tps6238x0-regulator.c -- TI tps623850/tps623860/tps623870
+ *
+ * Driver for processor core supply tps623850, tps623860 and tps623870
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps6238x0-regulator.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+/* Register definitions */
+#define REG_VSET0 0
+#define REG_VSET1 1
+#define REG_MODE0 2
+#define REG_MODE1 3
+#define REG_CONTROL 4
+#define REG_EXCEPTION 5
+#define REG_RAMPCTRL 6
+#define REG_IOUT 7
+#define REG_CHIPID 8
+
+#define TPS6238X0_BASE_VOLTAGE 500000
+#define TPS6238X0_N_VOLTAGES 128
+#define TPS6238X0_MAX_VSET 2
+#define TPS6238X0_VOUT_MASK 0x7F
+
+/* tps 6238x0 chip information */
+struct tps6238x0_chip {
+ const char *name;
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ int vsel_gpio;
+ int change_uv_per_us;
+ bool en_internal_pulldn;
+ bool valid_gpios;
+ int lru_index[TPS6238X0_MAX_VSET];
+ int curr_vset_vsel[TPS6238X0_MAX_VSET];
+ int curr_vset_id;
+};
+
+/*
+ * find_voltage_set_register: Find new voltage configuration register
+ * (VSET) id.
+ * The finding of the new VSET register will be based on the LRU mechanism.
+ * Each VSET register will have different voltage configured . This
+ * Function will look if any of the VSET register have requested voltage set
+ * or not.
+ * - If it is already there then it will make that register as most
+ * recently used and return as found so that caller need not to set
+ * the VSET register but need to set the proper gpios to select this
+ * VSET register.
+ * - If requested voltage is not found then it will use the least
+ * recently mechanism to get new VSET register for new configuration
+ * and will return not_found so that caller need to set new VSET
+ * register and then gpios (both).
+ */
+static bool find_voltage_set_register(struct tps6238x0_chip *tps,
+ int req_vsel, int *vset_reg_id)
+{
+ int i;
+ bool found = false;
+ int new_vset_reg = tps->lru_index[1];
+ int found_index = 1;
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) {
+ new_vset_reg = tps->lru_index[i];
+ found_index = i;
+ found = true;
+ goto update_lru_index;
+ }
+ }
+
+update_lru_index:
+ for (i = found_index; i > 0; i--)
+ tps->lru_index[i] = tps->lru_index[i - 1];
+
+ tps->lru_index[0] = new_vset_reg;
+ *vset_reg_id = new_vset_reg;
+ return found;
+}
+
+static int tps6238x0_get_voltage_sel(struct regulator_dev *dev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(dev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s: Error in reading register %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id);
+ return ret;
+ }
+ return data & TPS6238X0_VOUT_MASK;
+}
+
+static int tps6238x0_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(dev);
+ int vsel;
+ int ret;
+ bool found = false;
+ int new_vset_id = tps->curr_vset_id;
+
+ if (min_uV >
+ ((TPS6238X0_BASE_VOLTAGE + (TPS6238X0_N_VOLTAGES - 1) * 10000)))
+ return -EINVAL;
+
+ if ((max_uV < min_uV) || (max_uV < TPS6238X0_BASE_VOLTAGE))
+ return -EINVAL;
+
+ vsel = DIV_ROUND_UP(min_uV - TPS6238X0_BASE_VOLTAGE, 10000);
+ if (selector)
+ *selector = (vsel & TPS6238X0_VOUT_MASK);
+
+ /*
+ * If gpios are available to select the VSET register then least
+ * recently used register for new configuration.
+ */
+ if (tps->valid_gpios)
+ found = find_voltage_set_register(tps, vsel, &new_vset_id);
+
+ if (!found) {
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id,
+ TPS6238X0_VOUT_MASK, vsel);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s: Error in updating register %d\n",
+ __func__, REG_VSET0 + new_vset_id);
+ return ret;
+ }
+ tps->curr_vset_id = new_vset_id;
+ tps->curr_vset_vsel[new_vset_id] = vsel;
+ }
+
+ /* Select proper VSET register vio gpios */
+ if (tps->valid_gpios)
+ gpio_set_value_cansleep(tps->vsel_gpio, new_vset_id & 0x1);
+ return 0;
+}
+
+static int tps6238x0_list_voltage(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(dev);
+
+ if ((selector < 0) || (selector >= tps->desc.n_voltages))
+ return -EINVAL;
+
+ return TPS6238X0_BASE_VOLTAGE + selector * 10000;
+}
+
+static int tps6238x0_regulator_enable_time(struct regulator_dev *rdev)
+{
+ return 300;
+}
+
+static int tps6238x0_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+ old_uV = tps6238x0_list_voltage(rdev, old_selector);
+
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = tps6238x0_list_voltage(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV),
+ tps->change_uv_per_us);
+}
+
+static int tps6238x0_is_enable(struct regulator_dev *rdev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s: Error in reading register %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id);
+ return ret;
+ }
+ return !!(data & BIT(7));
+}
+
+static int tps6238x0_enable(struct regulator_dev *rdev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ int ret;
+ int i;
+
+ /* Enable required VSET configuration */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ unsigned int en = 0;
+ if (tps->valid_gpios || (i == tps->curr_vset_id))
+ en = BIT(7);
+
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + i,
+ BIT(7), en);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_VSET0 + i);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int tps6238x0_disable(struct regulator_dev *rdev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ int ret;
+ int i;
+
+ /* Disable required VSET configuration */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + i,
+ BIT(7), 0);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_VSET0 + i);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static struct regulator_ops tps6238x0_ops = {
+ .is_enabled = tps6238x0_is_enable,
+ .enable = tps6238x0_enable,
+ .disable = tps6238x0_disable,
+ .enable_time = tps6238x0_regulator_enable_time,
+ .set_voltage_time_sel = tps6238x0_set_voltage_time_sel,
+ .get_voltage_sel = tps6238x0_get_voltage_sel,
+ .set_voltage = tps6238x0_set_voltage,
+ .list_voltage = tps6238x0_list_voltage,
+};
+
+static int __devinit tps6238x0_configure(struct tps6238x0_chip *tps,
+ struct tps6238x0_regulator_platform_data *pdata)
+{
+ int ret;
+ int i;
+
+ /* Initailize internal pull up/down control */
+ if (tps->en_internal_pulldn)
+ ret = regmap_write(tps->regmap, REG_CONTROL, 0xC0);
+ else
+ ret = regmap_write(tps->regmap, REG_CONTROL, 0x0);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in writing reg %d\n",
+ __func__, REG_CONTROL);
+ return ret;
+ }
+
+ /* Enable required VSET configuration */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ unsigned int en = 0;
+ if (tps->valid_gpios || (i == tps->curr_vset_id))
+ en = BIT(7);
+
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + i,
+ BIT(7), en);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_VSET0 + i);
+ return ret;
+ }
+ }
+
+ /* Enable output discharge path to have faster discharge */
+ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2));
+ if (ret < 0)
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_RAMPCTRL);
+ tps->change_uv_per_us = 312;
+ return ret;
+}
+
+static const struct regmap_config tps6238x0_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_CHIPID,
+ .num_reg_defaults_raw = REG_CHIPID + 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tps6238x0_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tps6238x0_regulator_platform_data *pdata;
+ struct regulator_dev *rdev;
+ struct tps6238x0_chip *tps;
+ int ret;
+ int i;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "%s() Err: Platform data not found\n",
+ __func__);
+ return -EIO;
+ }
+
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps) {
+ dev_err(&client->dev, "%s() Err: Memory allocation fails\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ tps->en_internal_pulldn = pdata->en_internal_pulldn;
+ tps->vsel_gpio = pdata->vsel_gpio;
+ tps->dev = &client->dev;
+
+ tps->desc.name = id->name;
+ tps->desc.id = 0;
+ tps->desc.n_voltages = TPS6238X0_N_VOLTAGES;
+ tps->desc.ops = &tps6238x0_ops;
+ tps->desc.type = REGULATOR_VOLTAGE;
+ tps->desc.owner = THIS_MODULE;
+ tps->regmap = devm_regmap_init_i2c(client, &tps6238x0_regmap_config);
+ if (IS_ERR(tps->regmap)) {
+ ret = PTR_ERR(tps->regmap);
+ dev_err(&client->dev, "%s() Err: Failed to allocate register"
+ "map: %d\n", __func__, ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, tps);
+
+ tps->curr_vset_id = (pdata->vsel_def_state & 1);
+ tps->lru_index[0] = tps->curr_vset_id;
+ tps->valid_gpios = false;
+
+ if (gpio_is_valid(tps->vsel_gpio)) {
+ int gpio_flag;
+ gpio_flag = (tps->curr_vset_id) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(tps->vsel_gpio,
+ gpio_flag, "tps6238x0-vsel0");
+ if (ret) {
+ dev_err(&client->dev,
+ "Err: Could not obtain vsel GPIO %d: %d\n",
+ tps->vsel_gpio, ret);
+ return ret;
+ }
+ tps->valid_gpios = true;
+
+ /*
+ * Initialize the lru index with vset_reg id
+ * The index 0 will be most recently used and
+ * set with the tps->curr_vset_id */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i)
+ tps->lru_index[i] = i;
+ tps->lru_index[0] = tps->curr_vset_id;
+ tps->lru_index[tps->curr_vset_id] = 0;
+ }
+
+ ret = tps6238x0_configure(tps, pdata);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() Err: Init fails with = %d\n",
+ __func__, ret);
+ goto err_init;
+ }
+
+ /* Register the regulators */
+ rdev = regulator_register(&tps->desc, &client->dev,
+ pdata->init_data, tps);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "%s() Err: Failed to register %s\n",
+ __func__, id->name);
+ ret = PTR_ERR(rdev);
+ goto err_init;
+ }
+
+ tps->rdev = rdev;
+ return 0;
+
+err_init:
+ if (gpio_is_valid(tps->vsel_gpio))
+ gpio_free(tps->vsel_gpio);
+
+ return ret;
+}
+
+/**
+ * tps6238x0_remove - tps62360 driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister TPS driver as an i2c client device driver
+ */
+static int __devexit tps6238x0_remove(struct i2c_client *client)
+{
+ struct tps6238x0_chip *tps = i2c_get_clientdata(client);
+
+ if (gpio_is_valid(tps->vsel_gpio))
+ gpio_free(tps->vsel_gpio);
+
+ regulator_unregister(tps->rdev);
+ return 0;
+}
+
+static const struct i2c_device_id tps6238x0_id[] = {
+ {.name = "tps623850", },
+ {.name = "tps623860", },
+ {.name = "tps623870", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, tps6238x0_id);
+
+static struct i2c_driver tps6238x0_i2c_driver = {
+ .driver = {
+ .name = "tps6238x0",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps6238x0_probe,
+ .remove = __devexit_p(tps6238x0_remove),
+ .id_table = tps6238x0_id,
+};
+
+static int __init tps6238x0_init(void)
+{
+ return i2c_add_driver(&tps6238x0_i2c_driver);
+}
+subsys_initcall(tps6238x0_init);
+
+static void __exit tps6238x0_cleanup(void)
+{
+ i2c_del_driver(&tps6238x0_i2c_driver);
+}
+module_exit(tps6238x0_cleanup);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("TPS623850/TPS623860/TPS623870 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-tps6591x.c b/drivers/rtc/rtc-tps6591x.c
index cab3e8874dff..ebc46b4cf46e 100644
--- a/drivers/rtc/rtc-tps6591x.c
+++ b/drivers/rtc/rtc-tps6591x.c
@@ -3,7 +3,7 @@
*
* RTC driver for TI TPS6591x
*
- * 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 as published by
@@ -162,7 +162,7 @@ static int tps6591x_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_hour = buff[2];
tm->tm_mday = buff[3];
tm->tm_mon = buff[4] - 1;
- tm->tm_year = buff[5];
+ tm->tm_year = buff[5] + RTC_YEAR_OFFSET;
tm->tm_wday = buff[6];
print_time(dev, tm);
return tps6591x_rtc_valid_tm(tm);
@@ -250,7 +250,7 @@ static int tps6591x_rtc_set_time(struct device *dev, struct rtc_time *tm)
buff[2] = tm->tm_hour;
buff[3] = tm->tm_mday;
buff[4] = tm->tm_mon + 1;
- buff[5] = tm->tm_year;
+ buff[5] = tm->tm_year % RTC_YEAR_OFFSET;
buff[6] = tm->tm_wday;
print_time(dev, tm);
@@ -276,6 +276,42 @@ static int tps6591x_rtc_set_time(struct device *dev, struct rtc_time *tm)
return 0;
}
+static int tps6591x_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enable)
+{
+ struct tps6591x_rtc *rtc = dev_get_drvdata(dev);
+ u8 reg;
+ int err;
+
+ if (rtc->irq == -1)
+ return -EIO;
+
+ if (enable) {
+ if (rtc->irq_en == true)
+ return 0;
+ err = tps6591x_read_regs(dev, RTC_INT, 1, &reg);
+ if (err)
+ return err;
+ reg |= 0x8;
+ err = tps6591x_write_regs(dev, RTC_INT, 1, &reg);
+ if (err)
+ return err;
+ rtc->irq_en = true;
+ } else {
+ if (rtc->irq_en == false)
+ return 0;
+ err = tps6591x_read_regs(dev, RTC_INT, 1, &reg);
+ if (err)
+ return err;
+ reg &= ~0x8;
+ err = tps6591x_write_regs(dev, RTC_INT, 1, &reg);
+ if (err)
+ return err;
+ rtc->irq_en = false;
+ }
+ return 0;
+}
+
static int tps6591x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct tps6591x_rtc *rtc = dev_get_drvdata(dev);
@@ -298,10 +334,10 @@ static int tps6591x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return -EINVAL;
}
- if (alrm->enabled && !rtc->irq_en) {
- rtc->irq_en = true;
- } else if (!alrm->enabled && rtc->irq_en) {
- rtc->irq_en = false;
+ err = tps6591x_rtc_alarm_irq_enable(dev, alrm->enabled);
+ if(err) {
+ dev_err(dev->parent, "\n can't set alarm irq\n");
+ return err;
}
buff[0] = alrm->time.tm_sec;
@@ -309,7 +345,7 @@ static int tps6591x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
buff[2] = alrm->time.tm_hour;
buff[3] = alrm->time.tm_mday;
buff[4] = alrm->time.tm_mon + 1;
- buff[5] = alrm->time.tm_year;
+ buff[5] = alrm->time.tm_year % RTC_YEAR_OFFSET;
convert_decimal_to_bcd(buff, sizeof(buff));
err = tps6591x_write_regs(dev, RTC_ALARM, sizeof(buff), buff);
if (err)
@@ -333,7 +369,7 @@ static int tps6591x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_hour = buff[2];
alrm->time.tm_mday = buff[3];
alrm->time.tm_mon = buff[4] - 1;
- alrm->time.tm_year = buff[5];
+ alrm->time.tm_year = buff[5] + RTC_YEAR_OFFSET;
dev_info(dev->parent, "\n getting alarm time::\n");
print_time(dev, &alrm->time);
@@ -341,42 +377,6 @@ static int tps6591x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return 0;
}
-static int tps6591x_rtc_alarm_irq_enable(struct device *dev,
- unsigned int enable)
-{
- struct tps6591x_rtc *rtc = dev_get_drvdata(dev);
- u8 reg;
- int err;
-
- if (rtc->irq == -1)
- return -EIO;
-
- if (enable) {
- if (rtc->irq_en == true)
- return 0;
- err = tps6591x_read_regs(dev, RTC_INT, 1, &reg);
- if (err)
- return err;
- reg |= 0x8;
- err = tps6591x_write_regs(dev, RTC_INT, 1, &reg);
- if (err)
- return err;
- rtc->irq_en = true;
- } else {
- if (rtc->irq_en == false)
- return 0;
- err = tps6591x_read_regs(dev, RTC_INT, 1, &reg);
- if (err)
- return err;
- reg &= ~0x8;
- err = tps6591x_write_regs(dev, RTC_INT, 1, &reg);
- if (err)
- return err;
- rtc->irq_en = false;
- }
- return 0;
-}
-
static const struct rtc_class_ops tps6591x_rtc_ops = {
.read_time = tps6591x_rtc_read_time,
.set_time = tps6591x_rtc_set_time,
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index 3f913389dd7c..4901114f746c 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -441,7 +441,8 @@ static void spi_tegra_copy_client_txbuf_to_spi_txbuf(
/* Make the dma buffer to read by cpu */
dma_sync_single_for_cpu(&tspi->pdev->dev, tspi->tx_buf_phys,
- tspi->dma_buf_size, DMA_FROM_DEVICE);
+ tspi->dma_buf_size, DMA_TO_DEVICE);
+
if (tspi->is_packed) {
len = tspi->curr_dma_words * tspi->bytes_per_word;
memcpy(tspi->tx_buf, t->tx_buf + tspi->cur_pos, len);
@@ -461,6 +462,7 @@ static void spi_tegra_copy_client_txbuf_to_spi_txbuf(
}
}
tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+
/* Make the dma buffer to read by dma */
dma_sync_single_for_device(&tspi->pdev->dev, tspi->tx_buf_phys,
tspi->dma_buf_size, DMA_TO_DEVICE);
@@ -499,7 +501,7 @@ static void spi_tegra_copy_spi_rxbuf_to_client_rxbuf(
/* Make the dma buffer to read by dma */
dma_sync_single_for_device(&tspi->pdev->dev, tspi->rx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
}
static int spi_tegra_start_dma_based_transfer(
@@ -547,9 +549,6 @@ static int spi_tegra_start_dma_based_transfer(
if (tspi->cur_direction & DATA_DIR_TX) {
spi_tegra_copy_client_txbuf_to_spi_txbuf(tspi, t);
wmb();
- /* Make the dma buffer to read by dma */
- dma_sync_single_for_device(&tspi->pdev->dev, tspi->tx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
tspi->tx_dma_req.size = len;
ret = tegra_dma_enqueue_req(tspi->tx_dma, &tspi->tx_dma_req);
if (ret < 0) {
@@ -567,7 +566,8 @@ static int spi_tegra_start_dma_based_transfer(
if (tspi->cur_direction & DATA_DIR_RX) {
/* Make the dma buffer to read by dma */
dma_sync_single_for_device(&tspi->pdev->dev, tspi->rx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+
tspi->rx_dma_req.size = len;
ret = tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req);
if (ret < 0) {
@@ -1265,7 +1265,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
sprintf(tspi->port_name, "tegra_spi_%d", pdev->id);
ret = request_threaded_irq(tspi->irq, spi_tegra_isr,
- spi_tegra_isr_thread, IRQF_DISABLED,
+ spi_tegra_isr_thread, IRQF_ONESHOT,
tspi->port_name, tspi);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
@@ -1344,10 +1344,6 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
goto fail_rx_buf_alloc;
}
- /* Make the dma buffer to read by dma */
- dma_sync_single_for_device(&tspi->pdev->dev, tspi->rx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
-
memset(&tspi->rx_dma_req, 0, sizeof(struct tegra_dma_req));
tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
tspi->rx_dma_req.to_memory = 1;
@@ -1377,10 +1373,6 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
goto fail_tx_buf_alloc;
}
- /* Make the dma buffer to read by dma */
- dma_sync_single_for_device(&tspi->pdev->dev, tspi->tx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
-
memset(&tspi->tx_dma_req, 0, sizeof(struct tegra_dma_req));
tspi->tx_dma_req.complete = tegra_spi_tx_dma_complete;
tspi->tx_dma_req.to_memory = 0;
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index f5c226cc1689..7d22559e54c4 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1120,13 +1120,8 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
sg_dma_address(sg) = dma->tx_buf_dma + sg->offset;
}
sg = dma->sg_tx_p;
-<<<<<<< HEAD
- desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx,
- sg, num, DMA_TO_DEVICE,
-=======
desc_tx = dmaengine_prep_slave_sg(dma->chan_tx,
sg, num, DMA_MEM_TO_DEV,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n",
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index df8c8faad106..f20c82aa6d28 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -673,14 +673,9 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
/* Start the RX DMA job */
sgbuf = uap->dmarx.use_buf_b ?
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
-<<<<<<< HEAD
dma_dev = rxchan->device;
- desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
- DMA_FROM_DEVICE,
-=======
desc = dmaengine_prep_slave_sg(rxchan, &sgbuf->sg, 1,
DMA_DEV_TO_MEM,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
/*
* If the DMA engine is busy and cannot prepare a
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 5c33cefe2953..9748681679eb 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -910,13 +910,8 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
sg_dma_len(sg) = size;
}
-<<<<<<< HEAD
- desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
- priv->sg_tx_p, nent, DMA_TO_DEVICE,
-=======
desc = dmaengine_prep_slave_sg(priv->chan_tx,
priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3f4d9193b645..ef49f0a08364 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1328,13 +1328,8 @@ static void work_fn_tx(struct work_struct *work)
BUG_ON(!sg_dma_len(sg));
-<<<<<<< HEAD
- desc = chan->device->device_prep_slave_sg(chan,
- sg, s->sg_len_tx, DMA_TO_DEVICE,
-=======
desc = dmaengine_prep_slave_sg(chan,
sg, s->sg_len_tx, DMA_MEM_TO_DEV,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
/* switch to PIO */
diff --git a/drivers/tty/serial/tegra_hsuart.c b/drivers/tty/serial/tegra_hsuart.c
index 4169cbcbf299..8b65e20c4d3e 100644
--- a/drivers/tty/serial/tegra_hsuart.c
+++ b/drivers/tty/serial/tegra_hsuart.c
@@ -1638,7 +1638,7 @@ int tegra_uart_is_tx_empty(struct uart_port *uport)
return tegra_tx_empty(uport);
}
-static struct platform_driver tegra_uart_platform_driver = {
+static struct platform_driver tegra_uart_platform_driver __refdata= {
.probe = tegra_uart_probe,
.remove = __devexit_p(tegra_uart_remove),
.suspend = tegra_uart_suspend,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index a06f2cdc6106..8fb105e03658 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -204,6 +204,8 @@ static int acm_write_start(struct acm *acm, int wbn)
usb_mark_last_busy(acm->dev);
#ifdef CONFIG_PM
while ((res = usb_get_from_anchor(&acm->deferred))) {
+ /* decrement ref count*/
+ usb_put_urb(res);
rc = usb_submit_urb(res, GFP_ATOMIC);
if (rc < 0) {
dbg("usb_submit_urb(pending request) failed: %d", rc);
@@ -505,6 +507,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
goto out;
}
+ if (acm_submit_read_urbs(acm, GFP_KERNEL))
+ goto bail_out;
+
acm->ctrlurb->dev = acm->dev;
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
dev_err(&acm->control->dev,
@@ -518,9 +523,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
usb_autopm_put_interface(acm->control);
- if (acm_submit_read_urbs(acm, GFP_KERNEL))
- goto bail_out;
-
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
@@ -1303,6 +1305,7 @@ static void acm_disconnect(struct usb_interface *intf)
struct acm *acm = usb_get_intfdata(intf);
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct tty_struct *tty;
+ struct urb *res;
/* sibling interface is already cleaning up */
if (!acm)
@@ -1322,7 +1325,10 @@ static void acm_disconnect(struct usb_interface *intf)
stop_data_traffic(acm);
- usb_kill_anchored_urbs(&acm->deferred);
+ /* decrement ref count of anchored urbs */
+ while ((res = usb_get_from_anchor(&acm->deferred)))
+ usb_put_urb(res);
+
acm_write_buffers_free(acm);
usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
acm->ctrl_dma);
@@ -1425,6 +1431,8 @@ static int acm_resume(struct usb_interface *intf)
spin_lock_irq(&acm->write_lock);
#ifdef CONFIG_PM
while ((res = usb_get_from_anchor(&acm->deferred))) {
+ /* decrement ref count*/
+ usb_put_urb(res);
rv = usb_submit_urb(res, GFP_ATOMIC);
if (rv < 0) {
dbg("usb_submit_urb(pending request)"
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f92c3df69195..8e051d72d6aa 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -178,6 +178,17 @@ config USB_OMAP
dynamically linked module called "omap_udc" and force all
gadget drivers to also be dynamically linked.
+config USB_TEGRA
+ tristate "Nvidia Highspeed USB 2.0 device controller"
+ depends on ARCH_TEGRA
+ select USB_GADGET_DUALSPEED
+ help
+ Enables TEGRA USB 2.0 pheripheral driver.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "tegra_udc" and force all
+ gadget drivers to also be dynamically linked.
+
config USB_PXA25X
tristate "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 581a5ae7337e..fedd8eef4ae2 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -2,7 +2,7 @@
# USB peripheral controller drivers
#
GCOV_PROFILE_fsl_tegra_udc.o := y
-GCOV_PROFILE_fsl_udc_core.o := y
+GCOV_PROFILE_tegra_udc.o := y
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
@@ -22,7 +22,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
fsl_usb2_udc-y := fsl_udc_core.o
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
-fsl_usb2_udc-$(CONFIG_ARCH_TEGRA) += fsl_tegra_udc.o
+obj-$(CONFIG_USB_TEGRA) += tegra_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index c90e2d01f02c..e3196ba2833c 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -306,6 +306,11 @@ static void nuke(struct fsl_ep *ep, int status)
}
}
+static int can_pullup(struct fsl_udc *udc)
+{
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
/*------------------------------------------------------------------
Internal Hardware related function
------------------------------------------------------------------*/
@@ -485,19 +490,24 @@ static void dr_controller_run(struct fsl_udc *udc)
/* Set controller to Run */
temp = fsl_readl(&dr_regs->usbcmd);
- temp |= USB_CMD_RUN_STOP;
+ if (can_pullup(udc))
+ temp |= USB_CMD_RUN_STOP;
+ else
+ temp &= ~USB_CMD_RUN_STOP;
fsl_writel(temp, &dr_regs->usbcmd);
#ifdef CONFIG_ARCH_TEGRA
- /* Wait for controller to start */
- timeout = jiffies + FSL_UDC_RUN_TIMEOUT;
- while ((fsl_readl(&dr_regs->usbcmd) & USB_CMD_RUN_STOP) !=
- USB_CMD_RUN_STOP) {
- if (time_after(jiffies, timeout)) {
- ERR("udc start timeout!\n");
- return;
+ if (can_pullup(udc)) {
+ /* Wait for controller to start */
+ timeout = jiffies + FSL_UDC_RUN_TIMEOUT;
+ while ((fsl_readl(&dr_regs->usbcmd) & USB_CMD_RUN_STOP) !=
+ USB_CMD_RUN_STOP) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc start timeout!\n");
+ return;
+ }
+ cpu_relax();
}
- cpu_relax();
}
#endif
@@ -1374,10 +1384,6 @@ static int fsl_wakeup(struct usb_gadget *gadget)
}
#endif
-static int can_pullup(struct fsl_udc *udc)
-{
- return udc->driver && udc->softconnect && udc->vbus_active;
-}
static int fsl_set_selfpowered(struct usb_gadget * gadget, int is_on)
{
@@ -1397,64 +1403,47 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc = container_of(gadget, struct fsl_udc, gadget);
VDBG("VBUS %s", is_active ? "on" : "off");
-
- if (udc->transceiver) {
- if (udc->vbus_active && !is_active) {
- /* If cable disconnected, cancel any delayed work */
- cancel_delayed_work(&udc->work);
- spin_lock_irqsave(&udc->lock, flags);
- /* reset all internal Queues and inform client driver */
- reset_queues(udc);
- /* stop the controller and turn off the clocks */
- dr_controller_stop(udc);
- dr_controller_reset(udc);
- udc->vbus_active = 0;
- udc->usb_state = USB_STATE_DEFAULT;
- spin_unlock_irqrestore(&udc->lock, flags);
- fsl_udc_clk_suspend(false);
- if (udc->vbus_regulator) {
- /* set the current limit to 0mA */
- regulator_set_current_limit(
- udc->vbus_regulator, 0, 0);
- }
- } else if (!udc->vbus_active && is_active) {
- fsl_udc_clk_resume(false);
- /* setup the controller in the device mode */
- dr_controller_setup(udc);
- /* setup EP0 for setup packet */
- ep0_setup(udc);
- /* initialize the USB and EP states */
- udc->usb_state = USB_STATE_ATTACHED;
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = 0;
- udc->vbus_active = 1;
- /* start the controller */
- dr_controller_run(udc);
- if (udc->vbus_regulator) {
- /* set the current limit to 100mA */
- regulator_set_current_limit(
- udc->vbus_regulator, 0, 100);
- }
- /* Schedule work to wait for 1000 msec and check for
- * charger if setup packet is not received */
- schedule_delayed_work(&udc->work,
- USB_CHARGER_DETECTION_WAIT_TIME_MS);
+ if (udc->vbus_active && !is_active) {
+ /* If cable disconnected, cancel any delayed work */
+ cancel_delayed_work(&udc->work);
+ spin_lock_irqsave(&udc->lock, flags);
+ /* reset all internal Queues and inform client driver */
+ reset_queues(udc);
+ /* stop the controller and turn off the clocks */
+ dr_controller_stop(udc);
+ dr_controller_reset(udc);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ fsl_udc_clk_suspend(false);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 0mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 0);
}
-
-#ifndef CONFIG_USB_G_ANDROID
- return 0;
-#endif
+ } else if (!udc->vbus_active && is_active) {
+ fsl_udc_clk_resume(false);
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = 1;
+ /* start the controller */
+ dr_controller_run(udc);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 100mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 100);
+ }
+ /* Schedule work to wait for 1000 msec and check for
+ * charger if setup packet is not received */
+ schedule_delayed_work(&udc->work,
+ USB_CHARGER_DETECTION_WAIT_TIME_MS);
}
-
- spin_lock_irqsave(&udc->lock, flags);
- udc->vbus_active = (is_active != 0);
- if (can_pullup(udc))
- fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- else
- fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
@@ -1490,16 +1479,16 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
udc = container_of(gadget, struct fsl_udc, gadget);
udc->softconnect = (is_on != 0);
- if (udc_controller->transceiver) {
- if (udc_controller->transceiver->state == OTG_STATE_B_PERIPHERAL) {
- if (can_pullup(udc))
- fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- else
- fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- }
- }
+ if (udc_controller->transceiver &&
+ udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL)
+ return 0;
+
+ if (can_pullup(udc))
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+ &dr_regs->usbcmd);
+ else
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+ &dr_regs->usbcmd);
return 0;
}
@@ -2287,6 +2276,20 @@ static void fsl_udc_boost_cpu_frequency_work(struct work_struct* work)
}
#endif
+static void fsl_udc_irq_work(struct work_struct* irq_work)
+{
+ struct fsl_udc *udc = container_of (irq_work, struct fsl_udc, irq_work);
+ bool cable_connected = false;
+ u32 temp = 0;
+
+ temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
+ /* Check whether cable is connected*/
+ if (temp & USB_SYS_VBUS_STATUS)
+ fsl_vbus_session(&udc->gadget, 1);
+ else
+ fsl_vbus_session(&udc->gadget, 0);
+}
+
/*
* If VBUS is detected and setup packet is not received in 100ms then
* work thread starts and checks for the USB charger detection.
@@ -2319,12 +2322,12 @@ static void fsl_udc_restart(struct fsl_udc *udc)
/* setup EP0 for setup packet */
ep0_setup(udc);
/* start the controller */
+ udc->vbus_active = 1;
dr_controller_run(udc);
/* initialize the USB and EP states */
udc->usb_state = USB_STATE_ATTACHED;
udc->ep0_state = WAIT_FOR_SETUP;
udc->ep0_dir = 0;
- udc->vbus_active = 1;
}
#endif
@@ -2340,10 +2343,21 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
spin_lock_irqsave(&udc->lock, flags);
+ if (!udc->transceiver)
+ {
+ u32 temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
+ /* write back the register to clear the interrupt */
+ fsl_writel(temp, &usb_sys_regs->vbus_wakeup);
+ if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) {
+ schedule_work(&udc->irq_work);
+ }
+ status = IRQ_HANDLED;
+ }
+
/* Disable ISR for OTG host mode */
if (udc->stopped) {
spin_unlock_irqrestore(&udc->lock, flags);
- return IRQ_NONE;
+ return status;
}
#ifdef CONFIG_ARCH_TEGRA
@@ -2466,6 +2480,7 @@ static int fsl_start(struct usb_gadget_driver *driver,
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
+ udc_controller->vbus_active = vbus_enabled();
}
printk(KERN_INFO "%s: bind to driver %s\n",
@@ -3108,6 +3123,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
INIT_WORK(&udc_controller->boost_cpufreq_work, fsl_udc_boost_cpu_frequency_work);
pm_qos_add_request(&boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN, PM_QOS_DEFAULT_VALUE);
#endif
+ /* create a work for controlling the clocks to the phy if otg is disabled */
+ INIT_WORK(&udc_controller->irq_work, fsl_udc_irq_work);
/* Get the regulator for drawing the vbus current in udc driver */
udc_controller->vbus_regulator = regulator_get(NULL, "usb_bat_chg");
@@ -3136,6 +3153,10 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#endif
#endif
+ /* This should done ideally if board does not have pmu interrupt */
+ if (!udc_controller->transceiver)
+ fsl_udc_clk_enable();
+
return 0;
err_del_udc:
@@ -3267,23 +3288,16 @@ static int fsl_udc_resume(struct platform_device *pdev)
/* Detected VBUS set the transceiver state to device mode */
udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL;
}
+ } else {
+ fsl_udc_clk_resume(true);
}
fsl_udc_clk_resume(true);
-#if defined(CONFIG_ARCH_TEGRA)
- fsl_udc_restart(udc_controller);
-#else
- /* Enable DR irq reg and set controller Run */
- if (udc_controller->stopped) {
- dr_controller_setup(udc_controller);
- dr_controller_run(udc_controller);
- }
- udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = 0;
-#endif
+
/* Power down the phy if cable is not connected */
if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS))
fsl_udc_clk_suspend(false);
+ else
+ fsl_udc_restart(udc_controller);
return 0;
}
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 60055e77bf9a..814214f1c648 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -640,8 +640,9 @@ struct fsl_udc {
struct delayed_work work; /* delayed work for charger detection */
struct regulator *vbus_regulator; /* regulator for drawing VBUS */
u32 current_limit;
- struct work_struct charger_work; /* work for settting regulator current limit */
+ struct work_struct charger_work; /* work for setting regulator current limit */
struct work_struct boost_cpufreq_work; /* work for boosting cpu frequency */
+ struct work_struct irq_work; /* irq work for controlling the usb power*/
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index f3a83cd0ef50..db7f521e5d0a 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -49,6 +49,7 @@
#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name))
#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name))
#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
+#define gadget_is_tegra(g) (!strcmp("tegra-udc", (g)->name))
/**
* usb_gadget_controller_number - support bcdDevice id convention
@@ -115,7 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x30;
else if (gadget_is_net2272(gadget))
return 0x31;
-
+ else if (gadget_is_tegra(gadget))
+ return 0x32;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c
new file mode 100644
index 000000000000..978db7ece1de
--- /dev/null
+++ b/drivers/usb/gadget/tegra_udc.c
@@ -0,0 +1,2867 @@
+/*
+ * Copyright (C) 2012 NVIDIA Corporation
+ *
+ * Description:
+ * High-speed USB device controller driver.
+ * The driver is based on Freescale driver code from Li Yang and Jiang Bo.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#undef VERBOSE
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/dmapool.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/fsl_devices.h> /* check this */
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+
+#include <mach/usb_phy.h>
+#include <mach/iomap.h>
+
+#include "tegra_udc.h"
+
+/* #define IS_NEW_PHY_DRIVER 1 */
+
+#ifndef IS_NEW_PHY_DRIVER
+#include "fsl_tegra_udc.c"
+#endif
+
+#define DRIVER_DESC "Nvidia Tegra High-Speed USB SOC \
+ Device Controller driver"
+#define DRIVER_AUTHOR "Venkat Moganty/Rakesh Bodla"
+#define DRIVER_VERSION "Apr 30, 2012"
+#define USB1_PREFETCH_ID 6
+
+#define get_ep_by_pipe(udc, pipe) ((pipe == 1) ? &udc->eps[0] : \
+ &udc->eps[pipe])
+#define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \
+ * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
+
+#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF)
+#define ep_is_in(EP) ((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+ USB_DIR_IN) : ((EP)->desc->bEndpointAddress \
+ & USB_DIR_IN) == USB_DIR_IN)
+
+
+
+static const char driver_name[] = "tegra-udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+static void tegra_ep_fifo_flush(struct usb_ep *_ep);
+static int reset_queues(struct tegra_udc *udc);
+
+/*
+ * High speed test mode packet(53 bytes).
+ * See USB 2.0 spec, section 7.1.20.
+ */
+static const u8 tegra_udc_test_packet[53] = {
+ /* JKJKJKJK x9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK x8 */
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ /* JJJJKKKK x8 */
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ /* JJJJJJJKKKKKKK x8 */
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* JJJJJJJK x8 */
+ 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+ /* JKKKKKKK x10, JK */
+ 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+};
+
+static struct tegra_udc *the_udc;
+
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ static struct pm_qos_request_list boost_cpu_freq_req;
+ static u32 ep_queue_request_count;
+ static u8 boost_cpufreq_work_flag;
+#endif
+
+static inline void udc_writel(struct tegra_udc *udc, u32 val, u32 offset)
+{
+ writel(val, udc->regs + offset);
+}
+
+static inline unsigned int udc_readl(struct tegra_udc *udc, u32 offset)
+{
+ return readl(udc->regs + offset);
+}
+
+/* checks vbus status */
+static inline bool vbus_enabled(struct tegra_udc *udc)
+{
+ bool status = false;
+ status = (udc_readl(udc, VBUS_WAKEUP_REG_OFFSET) & USB_SYS_VBUS_STATUS);
+ return status;
+}
+
+/**
+ * done() - retire a request; caller blocked irqs
+ * @status : request status to be set, only works when
+ * request is still in progress.
+ */
+static void done(struct tegra_ep *ep, struct tegra_req *req, int status)
+{
+ struct tegra_udc *udc = NULL;
+ unsigned char stopped = ep->stopped;
+ struct ep_td_struct *curr_td, *next_td;
+ int j;
+
+ udc = (struct tegra_udc *)ep->udc;
+ /* Removed the req from tegra_ep->queue */
+ list_del_init(&req->queue);
+
+ /* req.status should be set as -EINPROGRESS in ep_queue() */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ /* Free dtd for the request */
+ next_td = req->head;
+ for (j = 0; j < req->dtd_count; j++) {
+ curr_td = next_td;
+ if (j != req->dtd_count - 1)
+ next_td = curr_td->next_td_virt;
+
+ dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
+ }
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ if (status && (status != -ESHUTDOWN))
+ VDBG("complete %s req %p stat %d len %u/%u",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ ep->stopped = 1;
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ if (req->req.complete && req->req.length >= BOOST_TRIGGER_SIZE) {
+ ep_queue_request_count--;
+ if (!ep_queue_request_count)
+ schedule_work(&udc->boost_cpufreq_work);
+ }
+#endif
+
+ spin_unlock(&ep->udc->lock);
+ /* complete() is from gadget layer,
+ * eg fsg->bulk_in_complete() */
+ if (req->req.complete)
+ req->req.complete(&ep->ep, &req->req);
+
+ spin_lock(&ep->udc->lock);
+ ep->stopped = stopped;
+}
+
+/*
+ * nuke(): delete all requests related to this ep
+ * called with spinlock held
+ */
+static void nuke(struct tegra_ep *ep, int status)
+{
+ ep->stopped = 1;
+
+ /* Flush fifo */
+ tegra_ep_fifo_flush(&ep->ep);
+
+ /* Whether this eq has request linked */
+ while (!list_empty(&ep->queue)) {
+ struct tegra_req *req = NULL;
+
+ req = list_entry(ep->queue.next, struct tegra_req, queue);
+ done(ep, req, status);
+ }
+}
+
+static int can_pullup(struct tegra_udc *udc)
+{
+ DBG("%s(%d) udc->softconnect = %d udc->vbus_active = %d\n",
+ __func__, __LINE__, udc->softconnect, udc->vbus_active);
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+static int dr_controller_reset(struct tegra_udc *udc)
+{
+ unsigned int tmp;
+ unsigned long timeout;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Stop and reset the usb controller */
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ tmp &= ~USB_CMD_RUN_STOP;
+ udc_writel(udc, tmp, USB_CMD_REG_OFFSET);
+
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ tmp |= USB_CMD_CTRL_RESET;
+ udc_writel(udc, tmp, USB_CMD_REG_OFFSET);
+
+ /* Wait for reset to complete */
+ timeout = jiffies + UDC_RESET_TIMEOUT_MS;
+ while (udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_CTRL_RESET) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc reset timeout!\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+static int dr_controller_setup(struct tegra_udc *udc)
+{
+ unsigned int tmp, portctrl;
+ unsigned long timeout;
+ int status;
+ unsigned int port_control_reg_offset;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (udc->has_hostpc)
+ port_control_reg_offset = USB_HOSTPCX_DEVLC_REG_OFFSET;
+ else
+ port_control_reg_offset = PORTSCX_REG_OFFSET;
+
+ /* Config PHY interface */
+ portctrl = udc_readl(udc, port_control_reg_offset);
+ portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+ portctrl |= PORTSCX_PTS_UTMI;
+ udc_writel(udc, portctrl, port_control_reg_offset);
+
+ status = dr_controller_reset(udc);
+ if (status)
+ return status;
+
+ /* Set the controller as device mode */
+ tmp = udc_readl(udc, USB_MODE_REG_OFFSET);
+ tmp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ tmp |= USB_MODE_SETUP_LOCK_OFF;
+ udc_writel(udc, tmp, USB_MODE_REG_OFFSET);
+
+ /* Wait for controller to switch to device mode */
+ timeout = jiffies + UDC_RESET_TIMEOUT_MS;
+ while ((udc_readl(udc, USB_MODE_REG_OFFSET) &
+ USB_MODE_CTRL_MODE_DEVICE) != USB_MODE_CTRL_MODE_DEVICE) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc device mode setup timeout!\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ /* Clear the setup status */
+ udc_writel(udc, 0, USB_STS_REG_OFFSET);
+
+ tmp = udc->ep_qh_dma;
+ tmp &= USB_EP_LIST_ADDRESS_MASK;
+ udc_writel(udc, tmp, USB_EP_LIST_ADDRESS_REG_OFFSET);
+
+ VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+ udc->ep_qh, (int)tmp,
+ udc_readl(udc, USB_EP_LIST_ADDRESS_REG_OFFSET));
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+/* Enable DR irq and set controller to run state */
+static void dr_controller_run(struct tegra_udc *udc)
+{
+ u32 temp;
+ unsigned long timeout;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Clear stopped bit */
+ udc->stopped = 0;
+
+ /* If OTG transceiver is available, then it handles the VBUS detection*/
+ if (!udc->transceiver) {
+ /* Enable cable detection interrupt, without setting the
+ * USB_SYS_VBUS_WAKEUP_INT bit. USB_SYS_VBUS_WAKEUP_INT is
+ * clear on write */
+ temp = udc_readl(udc, VBUS_WAKEUP_REG_OFFSET);
+ temp |= (USB_SYS_VBUS_WAKEUP_INT_ENABLE
+ | USB_SYS_VBUS_WAKEUP_ENABLE);
+ temp &= ~USB_SYS_VBUS_WAKEUP_INT_STATUS;
+ udc_writel(udc, temp, VBUS_WAKEUP_REG_OFFSET);
+ }
+ /* Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+ | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+ | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ udc_writel(udc, temp, USB_INTR_REG_OFFSET);
+
+ /* Set the controller as device mode */
+ temp = udc_readl(udc, USB_MODE_REG_OFFSET);
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ udc_writel(udc, temp, USB_MODE_REG_OFFSET);
+
+ /* Set controller to Run */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ if (can_pullup(udc))
+ temp |= USB_CMD_RUN_STOP;
+ else
+ temp &= ~USB_CMD_RUN_STOP;
+ udc_writel(udc, temp, USB_CMD_REG_OFFSET);
+
+ if (can_pullup(udc)) {
+ /* Wait for controller to start */
+ timeout = jiffies + UDC_RUN_TIMEOUT_MS;
+ while ((udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_RUN_STOP)
+ != USB_CMD_RUN_STOP) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc start timeout!\n");
+ return;
+ }
+ cpu_relax();
+ }
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return;
+}
+
+static void dr_controller_stop(struct tegra_udc *udc)
+{
+ unsigned int tmp;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Clear pending interrupt status bits */
+ tmp = udc_readl(udc, USB_STS_REG_OFFSET);
+ udc_writel(udc, tmp, USB_STS_REG_OFFSET);
+
+ /* disable all INTR */
+ udc_writel(udc, 0, USB_INTR_REG_OFFSET);
+
+ /* Set stopped bit for isr */
+ udc->stopped = 1;
+
+ /* set controller to Stop */
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ tmp &= ~USB_CMD_RUN_STOP;
+ udc_writel(udc, tmp, USB_CMD_REG_OFFSET);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return;
+}
+
+static void dr_ep_setup(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir, unsigned char ep_type)
+{
+ unsigned int tmp_epctrl = 0;
+
+ tmp_epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (dir) {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_TX_ENABLE;
+ tmp_epctrl |= ((unsigned int)(ep_type)
+ << EPCTRL_TX_EP_TYPE_SHIFT);
+ } else {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_RX_ENABLE;
+ tmp_epctrl |= ((unsigned int)(ep_type)
+ << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+
+ udc_writel(udc, tmp_epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+}
+
+static void dr_ep_change_stall(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir, int value)
+{
+ u32 tmp_epctrl = 0;
+
+ tmp_epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (value) {
+ /* set the stall bit */
+ if (dir)
+ tmp_epctrl |= EPCTRL_TX_EP_STALL;
+ else
+ tmp_epctrl |= EPCTRL_RX_EP_STALL;
+ } else {
+ /* clear the stall bit and reset data toggle */
+ if (dir) {
+ tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ } else {
+ tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ }
+ }
+ udc_writel(udc, tmp_epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+}
+
+/* Get stall status of a specific ep
+ Return: 0: not stalled; 1:stalled */
+static int dr_ep_get_stall(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir)
+{
+ u32 epctrl;
+
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (dir)
+ return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0;
+ else
+ return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0;
+}
+
+/**
+ * struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
+ * @zlt: Zero Length Termination Select (1: disable; 0: enable)
+ * @mult: Mult field
+ */
+static void struct_ep_qh_setup(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir, unsigned char ep_type,
+ unsigned int max_pkt_len, unsigned int zlt, unsigned char mult)
+{
+ struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir];
+ unsigned int tmp = 0;
+
+ /* set the Endpoint Capabilites in QH */
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ /* Interrupt On Setup (IOS). for control ep */
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+ | EP_QUEUE_HEAD_IOS;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+ | (mult << EP_QUEUE_HEAD_MULT_POS);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
+ break;
+ default:
+ VDBG("error ep type is %d", ep_type);
+ return;
+ }
+ if (zlt)
+ tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+
+ p_QH->max_pkt_length = cpu_to_le32(tmp);
+ p_QH->next_dtd_ptr = 1;
+ p_QH->size_ioc_int_sts = 0;
+
+ return;
+}
+
+/* Setup qh structure and ep register for ep0. */
+static void ep0_setup(struct tegra_udc *udc)
+{
+ /* the intialization of an ep includes: fields in QH, Regs,
+ * tegra_ep struct */
+ struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 1, 0);
+ struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 1, 0);
+ dr_ep_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+ dr_ep_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+
+ return;
+
+}
+
+/**
+ * when configurations are set, or when interface settings change
+ * for example the do_set_interface() in gadget layer,
+ * the driver will enable or disable the relevant endpoints
+ * ep0 doesn't use this routine. It is always enabled.
+ */
+static int tegra_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct tegra_udc *udc = NULL;
+ struct tegra_ep *ep = NULL;
+ unsigned short max = 0;
+ unsigned char mult = 0, zlt;
+ int retval = -EINVAL;
+ unsigned long flags = 0;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+
+ /* catch various bogus parameters */
+ if (!_ep || !desc || ep->desc
+ || (desc->bDescriptorType != USB_DT_ENDPOINT))
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+
+ max = le16_to_cpu(desc->wMaxPacketSize);
+
+ /* Disable automatic zlp generation. Driver is responsible to indicate
+ * explicitly through req->req.zero. This is needed to enable multi-td
+ * request.
+ */
+ zlt = 1;
+
+ /* Assume the max packet size from gadget is always correct */
+ switch (desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ /* mult = 0. Execute N Transactions as demonstrated by
+ * the USB variable length packet protocol where N is
+ * computed using the Maximum Packet Length (dQH) and
+ * the Total Bytes field (dTD) */
+ mult = 0;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ /* Calculate transactions needed for high bandwidth iso */
+ mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+ max = max & 0x7ff; /* bit 0~10 */
+ /* 3 transactions at most */
+ if (mult > 3)
+ goto en_done;
+ break;
+ default:
+ goto en_done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ ep->ep.maxpacket = max;
+ ep->desc = desc;
+ ep->stopped = 0;
+
+ /* Controller related setup
+ * Init EPx Queue Head (Ep Capabilites field in QH
+ * according to max, zlt, mult)
+ */
+ struct_ep_qh_setup(udc, (unsigned char) ep_index(ep),
+ (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+ ? USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK),
+ max, zlt, mult);
+
+ /* Init endpoint ctrl register */
+ dr_ep_setup(udc, (unsigned char) ep_index(ep),
+ (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+ ? USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK));
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ retval = 0;
+
+ VDBG("enabled %s (ep%d%s) maxpacket %d", ep->ep.name,
+ ep->desc->bEndpointAddress & 0x0f,
+ (desc->bEndpointAddress & USB_DIR_IN)
+ ? "in" : "out", max);
+en_done:
+ return retval;
+}
+
+/**
+ * @ep : the ep being unconfigured. May not be ep0
+ * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
+ */
+static int tegra_ep_disable(struct usb_ep *_ep)
+{
+ struct tegra_udc *udc = NULL;
+ struct tegra_ep *ep = NULL;
+
+ unsigned long flags = 0;
+ u32 epctrl;
+ int ep_num;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+ if (!_ep || !ep->desc) {
+ VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+ udc = (struct tegra_udc *)ep->udc;
+
+ /* disable ep on controller */
+ ep_num = ep_index(ep);
+
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled(udc)) {
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (ep_is_in(ep))
+ epctrl &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrl &= ~EPCTRL_RX_ENABLE;
+ udc_writel(udc, epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+ ep->desc = NULL;
+ ep->stopped = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ VDBG("disabled %s OK", _ep->name);
+ return 0;
+}
+
+/**
+ * Allocate a request object used by this endpoint
+ * the main operation is to insert the req->queue to the eq->queue
+ * Returns the request, or null if one could not be allocated
+ */
+static struct usb_request *
+tegra_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct tegra_req *req = NULL;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void tegra_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct tegra_req *req = NULL;
+
+ req = container_of(_req, struct tegra_req, req);
+
+ if (_req)
+ kfree(req);
+}
+
+static void tegra_queue_td(struct tegra_ep *ep, struct tegra_req *req)
+{
+ int i = ep_index(ep) * 2 + ep_is_in(ep);
+ u32 temp, bitmask, tmp_stat;
+ struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
+ struct tegra_udc *udc = ep->udc;
+
+ bitmask = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+
+ /* Flush all the dTD structs out to memory */
+ wmb();
+
+ /* check if the pipe is empty */
+ if (!(list_empty(&ep->queue))) {
+ /* Add td to the end */
+ struct tegra_req *lastreq;
+ lastreq = list_entry(ep->queue.prev, struct tegra_req, queue);
+ lastreq->tail->next_td_ptr =
+ cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
+ wmb();
+ /* Read prime bit, if 1 goto done */
+ if (udc_readl(udc, EP_PRIME_REG_OFFSET) & bitmask)
+ goto out;
+
+ do {
+ /* Set ATDTW bit in USBCMD */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ temp |= USB_CMD_ATDTW;
+ udc_writel(udc, temp, USB_CMD_REG_OFFSET);
+
+ /* Read correct status bit */
+ tmp_stat = udc_readl(udc, EP_STATUS_REG_OFFSET)
+ & bitmask;
+
+ } while (!(udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_ATDTW));
+
+ /* Write ATDTW bit to 0 */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ udc_writel(udc, temp & ~USB_CMD_ATDTW, USB_CMD_REG_OFFSET);
+
+ if (tmp_stat)
+ goto out;
+ }
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+ dQH->next_dtd_ptr = cpu_to_le32(temp);
+
+ /* Clear active and halt bit */
+ temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+ | EP_QUEUE_HEAD_STATUS_HALT));
+ dQH->size_ioc_int_sts &= temp;
+
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_memory_prefetch_on(udc->phy);
+#else
+ fsl_udc_ep_barrier();
+#endif
+
+ /* Ensure that updates to the QH will occur before priming. */
+ wmb();
+
+ /* Prime endpoint by writing 1 to ENDPTPRIME */
+ temp = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+ udc_writel(udc, temp, EP_PRIME_REG_OFFSET);
+out:
+ return;
+}
+
+/**
+ * Fill in the dTD structure
+ * @req : request that the transfer belongs to
+ * @length : return actually data length of the dTD
+ * @dma : return dma address of the dTD
+ * @is_last : return flag if it is the last dTD of the request
+ * return : pointer to the built dTD
+ */
+static struct ep_td_struct *tegra_build_dtd(struct tegra_req *req,
+ unsigned *length, dma_addr_t *dma, int *is_last, gfp_t gfp_flags)
+{
+ u32 swap_temp;
+ struct ep_td_struct *dtd;
+
+ /* how big will this transfer be? */
+ *length = min(req->req.length - req->req.actual,
+ (unsigned)EP_MAX_LENGTH_TRANSFER);
+
+ dtd = dma_pool_alloc(the_udc->td_pool, gfp_flags, dma);
+ if (dtd == NULL)
+ return dtd;
+
+ dtd->td_dma = *dma;
+ /* Clear reserved field */
+ swap_temp = cpu_to_le32(dtd->size_ioc_sts);
+ swap_temp &= ~DTD_RESERVED_FIELDS;
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ /* Init all of buffer page pointers */
+ swap_temp = (u32) (req->req.dma + req->req.actual);
+ dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+ dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+ dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+ dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+ dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
+
+ req->req.actual += *length;
+
+ /* zlp is needed if req->req.zero is set */
+ if (req->req.zero) {
+ if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+ *is_last = 1;
+ else
+ *is_last = 0;
+ } else if (req->req.length == req->req.actual)
+ *is_last = 1;
+ else
+ *is_last = 0;
+
+ if ((*is_last) == 0)
+ VDBG("multi-dtd request!");
+
+ /* Fill in the transfer size; set active bit */
+ swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
+
+ /* Enable interrupt for the last dtd of a request */
+ if (*is_last && !req->req.no_interrupt)
+ swap_temp |= DTD_IOC;
+
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ mb();
+
+ VDBG("length = %d address= 0x%x", *length, (int)*dma);
+
+ return dtd;
+}
+
+/* Generate dtd chain for a request */
+static int tegra_req_to_dtd(struct tegra_req *req, gfp_t gfp_flags)
+{
+ unsigned count;
+ int is_last;
+ int is_first = 1;
+ struct ep_td_struct *last_dtd = NULL, *dtd;
+ dma_addr_t dma;
+
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_memory_prefetch_off(the_udc->phy);
+#else
+ fsl_udc_dtd_prepare();
+#endif
+
+ do {
+ dtd = tegra_build_dtd(req, &count, &dma, &is_last, gfp_flags);
+ if (dtd == NULL)
+ return -ENOMEM;
+
+ if (is_first) {
+ is_first = 0;
+ req->head = dtd;
+ } else {
+ last_dtd->next_td_ptr = cpu_to_le32(dma);
+ last_dtd->next_td_virt = dtd;
+ }
+ last_dtd = dtd;
+
+ req->dtd_count++;
+ } while (!is_last);
+
+ dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
+
+ req->tail = dtd;
+
+ return 0;
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+tegra_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct tegra_ep *ep = container_of(_ep, struct tegra_ep, ep);
+ struct tegra_req *req = container_of(_req, struct tegra_req, req);
+ struct tegra_udc *udc = ep->udc;
+ unsigned long flags;
+ enum dma_data_direction dir;
+ int status;
+
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue)) {
+ VDBG("%s, bad params", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (unlikely(!ep->desc)) {
+ VDBG("%s, bad ep", __func__);
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EINVAL;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (req->req.length > ep->ep.maxpacket) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EMSGSIZE;
+ }
+ }
+
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ if (req->req.length >= BOOST_TRIGGER_SIZE) {
+ ep_queue_request_count++;
+ if (ep_queue_request_count && boost_cpufreq_work_flag)
+ schedule_work(&udc->boost_cpufreq_work);
+ }
+#endif
+
+ dir = ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ req->ep = ep;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(udc->gadget.dev.parent,
+ req->req.buf, req->req.length, dir);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(udc->gadget.dev.parent,
+ req->req.dma, req->req.length, dir);
+ req->mapped = 0;
+ }
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->dtd_count = 0;
+
+
+ /* build dtds and push them to device queue */
+ status = tegra_req_to_dtd(req, gfp_flags);
+ if (status)
+ goto err_unmap;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* re-check if the ep has not been disabled */
+ if (unlikely(!ep->desc)) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ status = -EINVAL;
+ goto err_unmap;
+ }
+
+ tegra_queue_td(ep, req);
+
+ /* Update ep0 state */
+ if ((ep_index(ep) == 0))
+ udc->ep0_state = DATA_STATE_XMIT;
+
+ /* irq handler advances the queue */
+ if (req != NULL)
+ list_add_tail(&req->queue, &ep->queue);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+
+err_unmap:
+ if (req->mapped) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ req->req.dma, req->req.length, dir);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+ return status;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int tegra_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct tegra_ep *ep = container_of(_ep, struct tegra_ep, ep);
+ struct tegra_req *req;
+ struct tegra_udc *udc = ep->udc;
+ unsigned long flags;
+ int ep_num, stopped, ret = 0;
+ u32 epctrl;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ stopped = ep->stopped;
+
+ /* Stop the ep before we deal with the queue */
+ ep->stopped = 1;
+ ep_num = ep_index(ep);
+
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled(udc)) {
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (ep_is_in(ep))
+ epctrl &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrl &= ~EPCTRL_RX_ENABLE;
+ udc_writel(udc, epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ }
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* The request is in progress, or completed but not dequeued */
+ if (ep->queue.next == &req->queue) {
+ _req->status = -ECONNRESET;
+ tegra_ep_fifo_flush(_ep); /* flush current transfer */
+
+ /* The request isn't the last request in this ep queue */
+ if (req->queue.next != &ep->queue) {
+ struct ep_queue_head *qh;
+ struct tegra_req *next_req;
+
+ qh = ep->qh;
+ next_req = list_entry(req->queue.next, struct tegra_req,
+ queue);
+
+ /* Point the QH to the first TD of next request */
+ writel((u32) next_req->head, &qh->curr_dtd_ptr);
+ }
+
+ /* The request hasn't been processed, patch up the TD chain */
+ } else {
+ struct tegra_req *prev_req;
+
+ prev_req = list_entry(req->queue.prev, struct tegra_req, queue);
+ writel(readl(&req->tail->next_td_ptr),
+ &prev_req->tail->next_td_ptr);
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ /* Enable EP */
+out:
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled(udc)) {
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (ep_is_in(ep))
+ epctrl |= EPCTRL_TX_ENABLE;
+ else
+ epctrl |= EPCTRL_RX_ENABLE;
+ udc_writel(udc, epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ }
+ ep->stopped = stopped;
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return ret;
+}
+
+/**
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt 0--clear halt
+ * Returns zero, or a negative error code.
+ */
+static int tegra_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct tegra_ep *ep = NULL;
+ unsigned long flags = 0;
+ int status = -EOPNOTSUPP; /* operation not supported */
+ unsigned char ep_dir = 0, ep_num = 0;
+ struct tegra_udc *udc = NULL;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+ udc = ep->udc;
+ if (!_ep || !ep->desc) {
+ status = -EINVAL;
+ goto out;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ status = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Attempt to halt IN ep will fail if any transfer requests
+ * are still queue */
+ if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+ status = -EAGAIN;
+ goto out;
+ }
+
+ status = 0;
+ ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+ ep_num = (unsigned char)(ep_index(ep));
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ dr_ep_change_stall(udc, ep_num, ep_dir, value);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ if (ep_index(ep) == 0) {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+out:
+ VDBG(" %s %s halt stat %d", ep->ep.name,
+ value ? "set" : "clear", status);
+
+ return status;
+}
+
+static int tegra_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct tegra_ep *ep;
+ struct tegra_udc *udc;
+ int size = 0;
+ u32 bitmask;
+ struct ep_queue_head *d_qh;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+ if (!_ep || (!ep->desc && ep_index(ep) != 0))
+ return -ENODEV;
+
+ udc = (struct tegra_udc *)ep->udc;
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
+
+ bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+ (1 << (ep_index(ep)));
+
+ if (udc_readl(udc, EP_STATUS_REG_OFFSET) & bitmask)
+ size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
+ >> DTD_LENGTH_BIT_POS;
+
+ pr_debug("%s %u\n", __func__, size);
+ return size;
+}
+
+static void tegra_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct tegra_ep *ep;
+ struct tegra_udc *udc;
+ int ep_num, ep_dir;
+ u32 bits;
+ unsigned long timeout;
+
+ if (!_ep) {
+ return;
+ } else {
+ ep = container_of(_ep, struct tegra_ep, ep);
+ if (!ep->desc)
+ return;
+ }
+ ep_num = ep_index(ep);
+ ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+ udc = ep->udc;
+
+ if (ep_num == 0)
+ bits = (1 << 16) | 1;
+ else if (ep_dir == USB_SEND)
+ bits = 1 << (16 + ep_num);
+ else
+ bits = 1 << ep_num;
+
+ /* Touch the registers if cable is connected and phy is on */
+ if (!vbus_enabled(udc))
+ return;
+
+ timeout = jiffies + UDC_FLUSH_TIMEOUT_MS;
+ do {
+ udc_writel(udc, bits, EPFLUSH_REG_OFFSET);
+
+ /* Wait until flush complete */
+ while (udc_readl(udc, EPFLUSH_REG_OFFSET)) {
+ if (time_after(jiffies, timeout)) {
+ ERR("ep flush timeout\n");
+ return;
+ }
+ cpu_relax();
+ }
+ /* See if we need to flush again */
+ } while (udc_readl(udc, EP_STATUS_REG_OFFSET) & bits);
+}
+
+static struct usb_ep_ops tegra_ep_ops = {
+ .enable = tegra_ep_enable,
+ .disable = tegra_ep_disable,
+
+ .alloc_request = tegra_alloc_request,
+ .free_request = tegra_free_request,
+
+ .queue = tegra_ep_queue,
+ .dequeue = tegra_ep_dequeue,
+
+ .set_halt = tegra_ep_set_halt,
+ .fifo_status = tegra_ep_fifo_status,
+ .fifo_flush = tegra_ep_fifo_flush, /* flush fifo */
+};
+
+/* Get the current frame number (from DR frame_index Reg ) */
+static int tegra_get_frame(struct usb_gadget *gadget)
+{
+ struct tegra_udc *udc = container_of(gadget, struct tegra_udc, gadget);
+ return (int)(udc_readl(udc, USB_FRINDEX_REG_OFFSET)
+ & USB_FRINDEX_MASKS);
+}
+
+#ifndef CONFIG_USB_ANDROID
+/* Tries to wake up the host connected to this gadget */
+static int tegra_wakeup(struct usb_gadget *gadget)
+{
+ struct tegra_udc *udc = container_of(gadget, struct tegra_udc, gadget);
+ u32 portsc;
+
+ /* Remote wakeup feature not enabled by host */
+ if (!udc->remote_wakeup)
+ return -ENOTSUPP;
+
+ portsc = udc_readl(udc, PORTSCX_REG_OFFSET);
+ /* not suspended? */
+ if (!(portsc & PORTSCX_PORT_SUSPEND))
+ return 0;
+
+ /* trigger force resume */
+ portsc |= PORTSCX_PORT_FORCE_RESUME;
+ udc_writel(udc, portsc, PORTSCX_REG_OFFSET);
+ return 0;
+}
+#endif
+
+static int tegra_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+ struct tegra_udc *udc;
+ udc = container_of(gadget, struct tegra_udc, gadget);
+ udc->selfpowered = (is_on != 0);
+ return 0;
+}
+
+/**
+ * Notify controller that VBUS is powered, Called by whatever
+ * detects VBUS sessions
+ */
+static int tegra_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct tegra_udc *udc = container_of(gadget, struct tegra_udc, gadget);
+
+ DBG("%s(%d) turn VBUS state from %s to %s", __func__, __LINE__,
+ udc->vbus_active ? "on" : "off", is_active ? "on" : "off");
+
+ if (udc->vbus_active && !is_active) {
+ /* If cable disconnected, cancel any delayed work */
+ cancel_delayed_work(&udc->work);
+ spin_lock(&udc->lock);
+ /* reset all internal Queues and inform client driver */
+ reset_queues(udc);
+ /* stop the controller and turn off the clocks */
+ dr_controller_stop(udc);
+ dr_controller_reset(udc);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock(&udc->lock);
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_off(udc->phy);
+#else
+ fsl_udc_clk_suspend(false);
+#endif
+ if (udc->vbus_reg) {
+ /* set the current limit to 0mA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0, 0);
+ }
+ } else if (!udc->vbus_active && is_active) {
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_on(udc->phy);
+#else
+ fsl_udc_clk_resume(false);
+#endif
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = 1;
+ /* start the controller */
+ dr_controller_run(udc);
+ if (udc->vbus_reg) {
+ /* set the current limit to 100mA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0, 100);
+ }
+ /* Schedule work to wait for 1000 msec and check for
+ * charger if setup packet is not received */
+ schedule_delayed_work(&udc->work,
+ USB_CHARGER_DETECTION_WAIT_TIME_MS);
+ }
+ return 0;
+}
+
+/**
+ * Constrain controller's VBUS power usage.
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume. For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int tegra_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct tegra_udc *udc;
+
+ udc = container_of(gadget, struct tegra_udc, gadget);
+ /* check udc regulator is available for drawing the vbus current */
+ if (udc->vbus_reg) {
+ udc->current_limit = mA;
+ schedule_work(&udc->charger_work);
+ }
+
+ if (udc->transceiver)
+ return otg_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+/**
+ * Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnect
+ */
+static int tegra_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct tegra_udc *udc;
+ u32 tmp;
+
+ udc = container_of(gadget, struct tegra_udc, gadget);
+ udc->softconnect = (is_on != 0);
+ if (udc->transceiver && udc->transceiver->state !=
+ OTG_STATE_B_PERIPHERAL)
+ return 0;
+
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ if (can_pullup(udc))
+ udc_writel(udc, tmp | USB_CMD_RUN_STOP,
+ USB_CMD_REG_OFFSET);
+ else
+ udc_writel(udc, (tmp & ~USB_CMD_RUN_STOP),
+ USB_CMD_REG_OFFSET);
+
+ return 0;
+}
+
+/* Release udc structures */
+static void tegra_udc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+
+ complete(udc->done);
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_close(udc->phy);
+#else
+ fsl_udc_clk_suspend(false);
+#endif
+
+ kfree(udc);
+}
+
+static int tegra_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int tegra_udc_stop(struct usb_gadget_driver *driver);
+/* defined in gadget.h */
+static struct usb_gadget_ops tegra_gadget_ops = {
+ .get_frame = tegra_get_frame,
+#ifndef CONFIG_USB_ANDROID
+ .wakeup = tegra_wakeup,
+#endif
+ .set_selfpowered = tegra_set_selfpowered,
+ .vbus_session = tegra_vbus_session,
+ .vbus_draw = tegra_vbus_draw,
+ .pullup = tegra_pullup,
+ .start = tegra_udc_start,
+ .stop = tegra_udc_stop,
+};
+
+static int tegra_udc_setup_gadget_dev(struct tegra_udc *udc)
+{
+ /* Setup gadget structure */
+ udc->gadget.ops = &tegra_gadget_ops;
+ udc->gadget.is_dualspeed = 1;
+ udc->gadget.ep0 = &udc->eps[0].ep;
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.name = driver_name;
+
+ /* Setup gadget.dev and register with kernel */
+ dev_set_name(&udc->gadget.dev, "gadget");
+ udc->gadget.dev.release = tegra_udc_release;
+ udc->gadget.dev.parent = &udc->pdev->dev;
+
+ return device_register(&udc->gadget.dev);
+}
+
+
+/**
+ * Set protocol stall on ep0, protocol stall will automatically be cleared
+ * on new transaction.
+ */
+static void ep0stall(struct tegra_udc *udc)
+{
+ u32 tmp;
+
+ /* must set tx and rx to stall at the same time */
+ tmp = udc_readl(udc, EP_CONTROL_REG_OFFSET);
+ tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+ udc_writel(udc, tmp, EP_CONTROL_REG_OFFSET);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+}
+
+/* Prime a status phase for ep0 */
+static int ep0_prime_status(struct tegra_udc *udc, int direction)
+{
+ struct tegra_req *req = udc->status_req;
+ struct tegra_ep *ep;
+
+ if (direction == EP_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ ep = &udc->eps[0];
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+
+ req->ep = ep;
+ req->req.length = 0;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ if (tegra_req_to_dtd(req, GFP_ATOMIC) == 0)
+ tegra_queue_td(ep, req);
+ else
+ return -ENOMEM;
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ return 0;
+}
+
+static void udc_reset_ep_queue(struct tegra_udc *udc, u8 pipe)
+{
+ struct tegra_ep *ep = get_ep_by_pipe(udc, pipe);
+
+ if (ep->name)
+ nuke(ep, -ESHUTDOWN);
+}
+
+/* ch9 Set address */
+static void ch9setaddress(struct tegra_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ /* Save the new address to device struct */
+ udc->device_address = (u8) value;
+ /* Update usb state */
+ udc->usb_state = USB_STATE_ADDRESS;
+ /* Status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+}
+
+/* ch9 Get status */
+static void ch9getstatus(struct tegra_udc *udc, u8 request_type, u16 value,
+ u16 index, u16 length)
+{
+ u16 tmp = 0; /* Status, cpu endian */
+ struct tegra_req *req;
+ struct tegra_ep *ep;
+
+ ep = &udc->eps[0];
+
+ if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ /* Get device status */
+ if (udc->selfpowered)
+ tmp = 1 << USB_DEVICE_SELF_POWERED;
+ tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+ /* Get interface status
+ * We don't have interface information in udc driver */
+ tmp = 0;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+ /* Get endpoint status */
+ struct tegra_ep *target_ep;
+
+ target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
+
+ /* stall if endpoint doesn't exist */
+ if (!target_ep->desc)
+ goto stall;
+ tmp = dr_ep_get_stall(udc, ep_index(target_ep),
+ ep_is_in(target_ep)) << USB_ENDPOINT_HALT;
+ }
+
+ udc->ep0_dir = USB_DIR_IN;
+ /* Borrow the per device status_req */
+ req = udc->status_req;
+ /* Fill in the reqest structure */
+ *((u16 *) req->req.buf) = cpu_to_le16(tmp);
+ req->ep = ep;
+ req->req.length = 2;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length, ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ /* prime the data phase */
+ if ((tegra_req_to_dtd(req, GFP_ATOMIC) == 0))
+ tegra_queue_td(ep, req);
+ else /* no mem */
+ goto stall;
+
+ list_add_tail(&req->queue, &ep->queue);
+ udc->ep0_state = DATA_STATE_XMIT;
+ return;
+stall:
+ ep0stall(udc);
+}
+
+static void udc_test_mode(struct tegra_udc *udc, u32 test_mode)
+{
+ struct tegra_req *req;
+ struct tegra_ep *ep;
+ u32 portsc, bitmask;
+ unsigned long timeout;
+
+ /* Ack the ep0 IN */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+
+ /* get the ep0 */
+ ep = &udc->eps[0];
+ bitmask = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+
+ timeout = jiffies + HZ;
+ /* Wait until ep0 IN endpoint txfr is complete */
+ while (!(udc_readl(udc, EP_COMPLETE_REG_OFFSET) & bitmask)) {
+ if (time_after(jiffies, timeout)) {
+ pr_err("Timeout for Ep0 IN Ack\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ switch (test_mode << PORTSCX_PTC_BIT_POS) {
+ case PORTSCX_PTC_JSTATE:
+ VDBG("TEST_J\n");
+ break;
+ case PORTSCX_PTC_KSTATE:
+ VDBG("TEST_K\n");
+ break;
+ case PORTSCX_PTC_SEQNAK:
+ VDBG("TEST_SE0_NAK\n");
+ break;
+ case PORTSCX_PTC_PACKET:
+ VDBG("TEST_PACKET\n");
+
+ /* get the ep and configure for IN direction */
+ ep = &udc->eps[0];
+ udc->ep0_dir = USB_DIR_IN;
+
+ /* Initialize ep0 status request structure */
+ req = container_of(tegra_alloc_request(NULL, GFP_ATOMIC),
+ struct tegra_req, req);
+ /* allocate a small amount of memory to get valid address */
+ req->req.buf = kmalloc(sizeof(tegra_udc_test_packet),
+ GFP_ATOMIC);
+ req->req.dma = virt_to_phys(req->req.buf);
+
+ /* Fill in the reqest structure */
+ memcpy(req->req.buf, tegra_udc_test_packet,
+ sizeof(tegra_udc_test_packet));
+ req->ep = ep;
+ req->req.length = sizeof(tegra_udc_test_packet);
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+ req->mapped = 0;
+
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ /* prime the data phase */
+ if ((tegra_req_to_dtd(req, GFP_ATOMIC) == 0))
+ tegra_queue_td(ep, req);
+ else /* no mem */
+ goto stall;
+
+ list_add_tail(&req->queue, &ep->queue);
+ udc->ep0_state = DATA_STATE_XMIT;
+ break;
+ case PORTSCX_PTC_FORCE_EN:
+ VDBG("TEST_FORCE_EN\n");
+ break;
+ default:
+ ERR("udc unknown test mode[%d]!\n", test_mode);
+ goto stall;
+ }
+
+ /* read the portsc register */
+ portsc = udc_readl(udc, PORTSCX_REG_OFFSET);
+ /* set the test mode selector */
+ portsc |= test_mode << PORTSCX_PTC_BIT_POS;
+ udc_writel(udc, portsc, PORTSCX_REG_OFFSET);
+
+ /*
+ * The device must have its power cycled to exit test mode.
+ * See USB 2.0 spec, section 9.4.9 for test modes operation
+ * in "Set Feature".
+ * See USB 2.0 spec, section 7.1.20 for test modes.
+ */
+ pr_info("udc entering the test mode, power cycle to exit test mode\n");
+ return;
+stall:
+ ep0stall(udc);
+}
+
+static void setup_received_irq(struct tegra_udc *udc,
+ struct usb_ctrlrequest *setup)
+{
+ u16 wValue = le16_to_cpu(setup->wValue);
+ u16 wIndex = le16_to_cpu(setup->wIndex);
+ u16 wLength = le16_to_cpu(setup->wLength);
+
+ udc_reset_ep_queue(udc, 0);
+
+ /* We process some stardard setup requests here */
+ switch (setup->bRequest) {
+ case USB_REQ_GET_STATUS:
+ /* Data+Status phase from udc */
+ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
+ != (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
+ return;
+
+ case USB_REQ_SET_ADDRESS:
+ /* Status phase from udc */
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
+ | USB_RECIP_DEVICE))
+ break;
+ /* This delay is necessary for some windows drivers to
+ * properly recognize the device */
+ mdelay(1);
+ ch9setaddress(udc, wValue, wIndex, wLength);
+ return;
+
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ /* Status phase from udc */
+ {
+ int rc = -EOPNOTSUPP;
+
+ if (setup->bRequestType == USB_RECIP_DEVICE &&
+ wValue == USB_DEVICE_TEST_MODE) {
+ /*
+ * If the feature selector is TEST_MODE, then the most
+ * significant byte of wIndex is used to specify the
+ * specific test mode and the lower byte of wIndex must
+ * be zero.
+ */
+ udc_test_mode(udc, wIndex >> 8);
+ return;
+
+ } else if ((setup->bRequestType &
+ (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+ (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
+ int pipe = get_pipe_by_windex(wIndex);
+ struct tegra_ep *ep;
+
+ if (wValue != 0 || wLength != 0 || pipe > udc->max_ep)
+ break;
+ ep = get_ep_by_pipe(udc, pipe);
+
+ spin_unlock(&udc->lock);
+ rc = tegra_ep_set_halt(&ep->ep,
+ (setup->bRequest == USB_REQ_SET_FEATURE)
+ ? 1 : 0);
+ spin_lock(&udc->lock);
+
+ } else if ((setup->bRequestType & (USB_RECIP_MASK
+ | USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+ | USB_TYPE_STANDARD)) {
+ /* Note: The driver has not include OTG support yet.
+ * This will be set when OTG support is added */
+ if (!gadget_is_otg(&udc->gadget))
+ break;
+ else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
+ udc->gadget.b_hnp_enable = 1;
+ else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+ udc->gadget.a_hnp_support = 1;
+ else if (setup->bRequest ==
+ USB_DEVICE_A_ALT_HNP_SUPPORT)
+ udc->gadget.a_alt_hnp_support = 1;
+ else
+ break;
+ rc = 0;
+ } else
+ break;
+
+ if (rc == 0) {
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+ }
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ /* Requests handled by gadget */
+ if (wLength) {
+ /* Data phase from gadget, status phase from udc */
+ udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+ ? USB_DIR_IN : USB_DIR_OUT;
+ spin_unlock(&udc->lock);
+ if (udc->driver && udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
+ ? DATA_STATE_XMIT : DATA_STATE_RECV;
+ } else {
+ /* No data phase, IN status from gadget */
+ udc->ep0_dir = USB_DIR_IN;
+ spin_unlock(&udc->lock);
+ if (udc->driver && udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
+}
+
+/* Process request for Data or Status phase of ep0
+ * prime status phase if needed */
+static void ep0_req_complete(struct tegra_udc *udc, struct tegra_ep *ep0,
+ struct tegra_req *req)
+{
+ if (udc->usb_state == USB_STATE_ADDRESS) {
+ /* Set the new address */
+ u32 new_address = (u32) udc->device_address;
+ udc_writel(udc, new_address << USB_DEVICE_ADDRESS_BIT_POS,
+ USB_DEVICE_ADDR_REG_OFFSET);
+ }
+
+ done(ep0, req, 0);
+
+ switch (udc->ep0_state) {
+ case DATA_STATE_XMIT:
+ /* receive status phase */
+ if (ep0_prime_status(udc, EP_DIR_OUT))
+ ep0stall(udc);
+ break;
+ case DATA_STATE_RECV:
+ /* send status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+ break;
+ case WAIT_FOR_OUT_STATUS:
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+ case WAIT_FOR_SETUP:
+ ERR("Unexpect ep0 packets\n");
+ break;
+ default:
+ ep0stall(udc);
+ break;
+ }
+}
+
+/* Tripwire mechanism to ensure a setup packet payload is extracted without
+ * being corrupted by another incoming setup packet */
+static void tripwire_handler(struct tegra_udc *udc, u8 ep_num, u8 *buffer_ptr)
+{
+ u32 temp;
+ struct ep_queue_head *qh;
+
+ qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
+
+ /* Clear bit in ENDPTSETUPSTAT */
+ temp = udc_readl(udc, EP_SETUP_STATUS_REG_OFFSET);
+ udc_writel(udc, temp | (1 << ep_num), EP_SETUP_STATUS_REG_OFFSET);
+
+ /* while a hazard exists when setup package arrives */
+ do {
+ /* Set Setup Tripwire */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ udc_writel(udc, temp | USB_CMD_SUTW, USB_CMD_REG_OFFSET);
+
+ /* Copy the setup packet to local buffer */
+ memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
+ } while (!(udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_SUTW));
+
+ /* Clear Setup Tripwire */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ udc_writel(udc, temp & ~USB_CMD_SUTW, USB_CMD_REG_OFFSET);
+}
+
+/* process-ep_req(): free the completed Tds for this req */
+static int process_ep_req(struct tegra_udc *udc, int pipe,
+ struct tegra_req *curr_req)
+{
+ struct ep_td_struct *curr_td;
+ int td_complete, actual, remaining_length, j, tmp;
+ int status = 0;
+ int errors = 0;
+ struct ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+ int direction = pipe % 2;
+
+ curr_td = curr_req->head;
+ td_complete = 0;
+ actual = curr_req->req.length;
+
+ for (j = 0; j < curr_req->dtd_count; j++) {
+ /* Fence read for coherency of AHB master intiated writes */
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+
+ dma_sync_single_for_cpu(udc->gadget.dev.parent, curr_td->td_dma,
+ sizeof(struct ep_td_struct), DMA_FROM_DEVICE);
+
+ remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_PACKET_SIZE)
+ >> DTD_LENGTH_BIT_POS;
+ actual -= remaining_length;
+ errors = le32_to_cpu(curr_td->size_ioc_sts);
+ if (errors & DTD_ERROR_MASK) {
+ if (errors & DTD_STATUS_HALTED) {
+ ERR("dTD error %08x QH=%d\n", errors, pipe);
+ /* Clear the errors and Halt condition */
+ tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
+ tmp &= ~errors;
+ curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
+ status = -EPIPE;
+ /* FIXME: continue with next queued TD? */
+
+ break;
+ }
+ if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+ VDBG("Transfer overflow");
+ status = -EPROTO;
+ break;
+ } else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+ VDBG("ISO error");
+ status = -EILSEQ;
+ break;
+ } else
+ ERR("Unknown error has occurred (0x%x)!\n",
+ errors);
+
+ } else if (le32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_STATUS_ACTIVE) {
+ VDBG("Request not complete");
+ status = REQ_UNCOMPLETE;
+ return status;
+ } else if (remaining_length) {
+ if (direction) {
+ VDBG("Transmit dTD remaining length not zero");
+ status = -EPROTO;
+ break;
+ } else {
+ td_complete++;
+ break;
+ }
+ } else {
+ td_complete++;
+ VDBG("dTD transmitted successful");
+ }
+
+ if (j != curr_req->dtd_count - 1)
+ curr_td = (struct ep_td_struct *)curr_td->next_td_virt;
+ }
+
+ if (status)
+ return status;
+
+ curr_req->req.actual = actual;
+
+ return 0;
+}
+
+/* Process a DTD completion interrupt */
+static void dtd_complete_irq(struct tegra_udc *udc)
+{
+ u32 bit_pos;
+ int i, ep_num, direction, bit_mask, status;
+ struct tegra_ep *curr_ep;
+ struct tegra_req *curr_req, *temp_req;
+
+ /* Clear the bits in the register */
+ bit_pos = udc_readl(udc, EP_COMPLETE_REG_OFFSET);
+ udc_writel(udc, bit_pos, EP_COMPLETE_REG_OFFSET);
+
+ if (!bit_pos)
+ return;
+
+ for (i = 0; i < udc->max_ep; i++) {
+ ep_num = i >> 1;
+ direction = i % 2;
+
+ bit_mask = 1 << (ep_num + 16 * direction);
+
+ if (!(bit_pos & bit_mask))
+ continue;
+
+ curr_ep = get_ep_by_pipe(udc, i);
+
+ /* If the ep is configured */
+ if (curr_ep->name == NULL) {
+ WARNING("Invalid EP?");
+ continue;
+ }
+
+ /* process the req queue until an uncomplete request */
+ list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,
+ queue) {
+ status = process_ep_req(udc, i, curr_req);
+
+ VDBG("status of process_ep_req= %d, ep = %d",
+ status, ep_num);
+ if (status == REQ_UNCOMPLETE)
+ break;
+ /* write back status to req */
+ curr_req->req.status = status;
+
+ if (ep_num == 0) {
+ ep0_req_complete(udc, curr_ep, curr_req);
+ break;
+ } else
+ done(curr_ep, curr_req, status);
+ }
+ }
+}
+
+/* Process a port change interrupt */
+static void port_change_irq(struct tegra_udc *udc)
+{
+ u32 speed;
+ unsigned int port_control_reg_offset;
+
+ if (udc->has_hostpc)
+ port_control_reg_offset = USB_HOSTPCX_DEVLC_REG_OFFSET;
+ else
+ port_control_reg_offset = PORTSCX_REG_OFFSET;
+
+ /* Bus resetting is finished */
+ if (!(udc_readl(udc, port_control_reg_offset) & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+ speed = (udc_readl(udc, port_control_reg_offset)
+ & PORTSCX_PORT_SPEED_MASK);
+ if (speed == PORTSCX_PORT_SPEED_HIGH)
+ udc->gadget.speed = USB_SPEED_HIGH;
+ else if (speed == PORTSCX_PORT_SPEED_FULL)
+ udc->gadget.speed = USB_SPEED_FULL;
+ else if (speed == PORTSCX_PORT_SPEED_LOW)
+ udc->gadget.speed = USB_SPEED_LOW;
+ else
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ }
+
+ /* Update USB state */
+ if (!udc->resume_state)
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+/* Process suspend interrupt */
+static void suspend_irq(struct tegra_udc *udc)
+{
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+
+ /* report suspend to the driver, serial.c does not support this */
+ if (udc->driver && udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+}
+
+static void bus_resume(struct tegra_udc *udc)
+{
+ udc->usb_state = udc->resume_state;
+ udc->resume_state = 0;
+
+ /* report resume to the driver, serial.c does not support this */
+ if (udc->driver && udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+/* Clear up all ep queues */
+static int reset_queues(struct tegra_udc *udc)
+{
+ u8 pipe;
+
+ for (pipe = 0; pipe < udc->max_pipes; pipe++)
+ udc_reset_ep_queue(udc, pipe);
+
+ /* report disconnect; the driver is already quiesced */
+ spin_unlock(&udc->lock);
+ if (udc->driver && udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+
+ return 0;
+}
+
+/* Process reset interrupt */
+static void reset_irq(struct tegra_udc *udc)
+{
+ u32 temp;
+ unsigned long timeout;
+
+ /* Clear the device address */
+ temp = udc_readl(udc, USB_DEVICE_ADDR_REG_OFFSET);
+ udc_writel(udc, temp & ~USB_DEVICE_ADDRESS_MASK,
+ USB_DEVICE_ADDR_REG_OFFSET);
+
+ udc->device_address = 0;
+
+ /* Clear usb state */
+ udc->resume_state = 0;
+ udc->ep0_dir = 0;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->remote_wakeup = 0; /* default to 0 on reset */
+ udc->gadget.b_hnp_enable = 0;
+ udc->gadget.a_hnp_support = 0;
+ udc->gadget.a_alt_hnp_support = 0;
+
+ /* Clear all the setup token semaphores */
+ temp = udc_readl(udc, EP_SETUP_STATUS_REG_OFFSET);
+ udc_writel(udc, temp, EP_SETUP_STATUS_REG_OFFSET);
+
+ /* Clear all the endpoint complete status bits */
+ temp = udc_readl(udc, EP_COMPLETE_REG_OFFSET);
+ udc_writel(udc, temp, EP_COMPLETE_REG_OFFSET);
+
+ timeout = jiffies + 100;
+ while (udc_readl(udc, EP_PRIME_REG_OFFSET)) {
+ /* Wait until all endptprime bits cleared */
+ if (time_after(jiffies, timeout)) {
+ ERR("Timeout for reset\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ /* Write 1s to the flush register */
+ udc_writel(udc, 0xffffffff, EPFLUSH_REG_OFFSET);
+
+ /* When the bus reset is seen on Tegra, the PORTSCX_PORT_RESET bit
+ * is not set. Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ VDBG("Bus reset");
+ reset_queues(udc);
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+static void tegra_udc_set_current_limit_work(struct work_struct *work)
+{
+ struct tegra_udc *udc = container_of(work, struct tegra_udc,
+ charger_work);
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_reg) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0,
+ udc->current_limit * 1000);
+ }
+}
+
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+static void tegra_udc_boost_cpu_frequency_work(struct work_struct *work)
+{
+ if (ep_queue_request_count && boost_cpufreq_work_flag) {
+ pm_qos_update_request(&boost_cpu_freq_req,
+ (s32)CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ * 1000);
+ boost_cpufreq_work_flag = 0;
+ } else if (!ep_queue_request_count && !boost_cpufreq_work_flag) {
+ pm_qos_update_request(&boost_cpu_freq_req,
+ PM_QOS_DEFAULT_VALUE);
+ boost_cpufreq_work_flag = 1;
+ }
+}
+#endif
+
+static void tegra_udc_irq_work(struct work_struct *irq_work)
+{
+ struct tegra_udc *udc = container_of(irq_work, struct tegra_udc,
+ irq_work);
+
+ /* Check whether cable is connected*/
+ if (vbus_enabled(udc))
+ tegra_vbus_session(&udc->gadget, 1);
+ else
+ tegra_vbus_session(&udc->gadget, 0);
+}
+
+/*
+ * If VBUS is detected and setup packet is not received in 100ms then
+ * work thread starts and checks for the USB charger detection.
+ */
+static void tegra_udc_charger_detect_work(struct work_struct *work)
+{
+ struct tegra_udc *udc = container_of(work, struct tegra_udc, work.work);
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* check for the platform charger detection */
+#ifdef IS_NEW_PHY_DRIVER
+ if (tegra_usb_phy_charger_detected(udc->phy)) {
+#else
+ if (fsl_udc_charger_detect()) {
+#endif
+ printk(KERN_INFO "USB compliant charger detected\n");
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_reg) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0,
+ USB_CHARGING_CURRENT_LIMIT_MA*1000);
+ }
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+}
+
+/* Restart device controller in the OTG mode on VBUS detection */
+static void tegra_udc_restart(struct tegra_udc *udc)
+{
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ udc->vbus_active = 1;
+ /* start the controller */
+ dr_controller_run(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+}
+
+/* USB device controller interrupt handler */
+static irqreturn_t tegra_udc_irq(int irq, void *_udc)
+{
+ struct tegra_udc *udc = _udc;
+ u32 irq_src, temp;
+ irqreturn_t status = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!udc->transceiver) {
+ temp = udc_readl(udc, VBUS_WAKEUP_REG_OFFSET);
+ /* write back the register to clear the interrupt */
+ udc_writel(udc, temp, VBUS_WAKEUP_REG_OFFSET);
+ if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS)
+ schedule_work(&udc->irq_work);
+ status = IRQ_HANDLED;
+ }
+
+ /* Disable ISR for OTG host mode */
+ if (udc->stopped) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return status;
+ }
+
+ /* Fence read for coherency of AHB master intiated writes */
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+
+ irq_src = udc_readl(udc, USB_STS_REG_OFFSET) &
+ udc_readl(udc, USB_INTR_REG_OFFSET);
+
+ /* Clear notification bits */
+ udc_writel(udc, irq_src, USB_STS_REG_OFFSET);
+
+ /* Need to resume? */
+ if (udc->usb_state == USB_STATE_SUSPENDED)
+ if (!(udc_readl(udc, PORTSCX_REG_OFFSET)
+ & PORTSCX_PORT_SUSPEND))
+ bus_resume(udc);
+
+ /* USB Interrupt */
+ if (irq_src & USB_STS_INT) {
+ VDBG("Packet int");
+ /* Setup package, we only support ep0 as control ep */
+ if (udc_readl(udc, EP_SETUP_STATUS_REG_OFFSET) &
+ EP_SETUP_STATUS_EP0) {
+ /* Setup packet received, we are connected to host
+ * and not to charger. Cancel any delayed work */
+ __cancel_delayed_work(&udc->work);
+ tripwire_handler(udc, 0,
+ (u8 *) (&udc->local_setup_buff));
+ setup_received_irq(udc, &udc->local_setup_buff);
+ status = IRQ_HANDLED;
+ }
+
+ /* completion of dtd */
+ if (udc_readl(udc, EP_COMPLETE_REG_OFFSET)) {
+ dtd_complete_irq(udc);
+ status = IRQ_HANDLED;
+ }
+ }
+
+ /* SOF (for ISO transfer) */
+ if (irq_src & USB_STS_SOF)
+ status = IRQ_HANDLED;
+
+ /* Port Change */
+ if (irq_src & USB_STS_PORT_CHANGE) {
+ port_change_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Reset Received */
+ if (irq_src & USB_STS_RESET) {
+ reset_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Sleep Enable (Suspend) */
+ if (irq_src & USB_STS_SUSPEND) {
+ suspend_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR))
+ VDBG("Error IRQ %x", irq_src);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return status;
+}
+
+/**
+ * Hook to gadget drivers
+ * Called by initialization code of gadget drivers
+ */
+static int tegra_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct tegra_udc *udc = the_udc;
+ int retval = -ENODEV;
+ unsigned long flags = 0;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (!udc)
+ return -ENODEV;
+
+
+
+ if (!driver || (driver->speed != USB_SPEED_FULL
+ && driver->speed != USB_SPEED_HIGH)
+ || !bind || !driver->disconnect
+ || !driver->setup)
+ return -EINVAL;
+
+ if (udc->driver)
+ return -EBUSY;
+
+ /* lock is needed but whether should use this lock or another */
+ spin_lock_irqsave(&udc->lock, flags);
+
+ driver->driver.bus = NULL;
+ /* hook up the driver */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* bind udc driver to gadget driver */
+ retval = bind(&udc->gadget);
+ if (retval) {
+ VDBG("bind to %s --> %d", driver->driver.name, retval);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+ goto out;
+ }
+
+
+ /* Enable DR IRQ reg and Set usbcmd reg Run bit */
+ if (!udc->transceiver) {
+ dr_controller_run(udc);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = vbus_enabled(udc);
+ }
+
+ printk(KERN_INFO "%s: bind to driver %s\n",
+ udc->gadget.name, driver->driver.name);
+
+out:
+ if (retval)
+ printk(KERN_WARNING "gadget driver register failed %d\n",
+ retval);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return retval;
+}
+
+/* Disconnect from gadget driver */
+static int tegra_udc_stop(struct usb_gadget_driver *driver)
+{
+ struct tegra_udc *udc = the_udc;
+ struct tegra_ep *loop_ep;
+ unsigned long flags;
+
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+ if (!udc)
+ return -ENODEV;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ /* stop DR, disable intr */
+ dr_controller_stop(udc);
+
+ /* in fact, no needed */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+
+ /* stand operation */
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc->gadget.ep_list,
+ ep.ep_list)
+ nuke(loop_ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* report disconnect; the controller is already quiesced */
+ driver->disconnect(&udc->gadget);
+
+ /* unbind gadget and unhook driver. */
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ printk(KERN_WARNING "unregistered gadget driver '%s'\n",
+ driver->driver.name);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+
+ return 0;
+}
+
+
+/* Internal structure setup functions */
+static int tegra_udc_setup_qh(struct tegra_udc *udc)
+{
+ u32 dccparams;
+ size_t size;
+
+ /* Read Device Controller Capability Parameters register */
+ dccparams = udc_readl(udc, DCCPARAMS_REG_OFFSET);
+ if (!(dccparams & DCCPARAMS_DC)) {
+ ERR("This SOC doesn't support device role\n");
+ return -ENODEV;
+ }
+
+ /* Get max device endpoints */
+ /* DEN is bidirectional ep number, max_ep doubles the number */
+ udc->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
+ udc->eps = kzalloc(sizeof(struct tegra_ep) * udc->max_ep, GFP_KERNEL);
+ if (!udc->eps) {
+ ERR("malloc tegra_ep failed\n");
+ return -1;
+ }
+
+ /* Setup hardware queue heads */
+ size = udc->max_ep * sizeof(struct ep_queue_head);
+ udc->ep_qh = (struct ep_queue_head *)((u8 *)(udc->regs) + QH_OFFSET);
+ udc->ep_qh_dma = platform_get_resource(udc->pdev, IORESOURCE_MEM
+ , 0)->start + QH_OFFSET;
+ udc->ep_qh_size = size;
+
+ /* Initialize ep0 status request structure */
+ /* FIXME: tegra_alloc_request() ignores ep argument */
+ udc->status_req = container_of(tegra_alloc_request(NULL, GFP_KERNEL),
+ struct tegra_req, req);
+ /* allocate a small amount of memory to get valid address */
+ udc->status_req->req.buf = dma_alloc_coherent(&udc->pdev->dev,
+ STATUS_BUFFER_SIZE, &udc->status_req->req.dma,
+ GFP_KERNEL);
+ if (!udc->status_req->req.buf) {
+ ERR("alloc status_req buffer failed\n");
+ kfree(udc->eps);
+ return -ENOMEM;
+ }
+
+ udc->resume_state = USB_STATE_NOTATTACHED;
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = 0;
+ udc->remote_wakeup = 0; /* default to 0 on reset */
+
+ return 0;
+}
+
+/**
+ * Setup the tegra_ep struct for eps
+ * Link tegra_ep->ep to gadget->ep_list
+ * ep0out is not used so do nothing here
+ * ep0in should be taken care
+ */
+static int __init struct_ep_setup(struct tegra_udc *udc, unsigned char index,
+ char *name, int link)
+{
+ struct tegra_ep *ep = &udc->eps[index];
+
+ ep->udc = udc;
+ strcpy(ep->name, name);
+ ep->ep.name = ep->name;
+
+ ep->ep.ops = &tegra_ep_ops;
+ ep->stopped = 0;
+
+ /* for ep0: maxP defined in desc
+ * for other eps, maxP is set by epautoconfig() called by gadget layer
+ */
+ ep->ep.maxpacket = (unsigned short) ~0;
+
+ /* the queue lists any req for this ep */
+ INIT_LIST_HEAD(&ep->queue);
+
+ /* gagdet.ep_list used for ep_autoconfig so no ep0 */
+ if (link)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->gadget = &udc->gadget;
+ ep->qh = &udc->ep_qh[index];
+
+ return 0;
+}
+
+static int tegra_udc_ep_setup(struct tegra_udc *udc)
+{
+ /* initialize EP0 descriptor */
+ static const struct usb_endpoint_descriptor tegra_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
+ };
+ int i;
+
+ /* setup QH and epctrl for ep0 */
+ ep0_setup(udc);
+
+ /* setup udc->eps[] for ep0 */
+ struct_ep_setup(udc, 0, "ep0", 0);
+ /* for ep0: the desc defined here;
+ * for other eps, gadget layer called ep_enable with defined desc
+ */
+ udc->eps[0].desc = &tegra_ep0_desc;
+ udc->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+
+ /* setup the udc->eps[] for non-control endpoints and link
+ * to gadget.ep_list */
+ for (i = 1; i < (int)(udc->max_ep / 2); i++) {
+ char name[14];
+
+ sprintf(name, "ep%dout", i);
+ struct_ep_setup(udc, i * 2, name, 1);
+ sprintf(name, "ep%din", i);
+ struct_ep_setup(udc, i * 2 + 1, name, 1);
+ }
+
+ return 0;
+}
+
+
+/* Driver probe function
+ * all intialization operations implemented here except enabling usb_intr reg
+ * board setup should have been done in the platform code
+ */
+static int __init tegra_udc_probe(struct platform_device *pdev)
+{
+ struct tegra_udc *udc;
+ struct resource *res;
+ int err = -ENODEV;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (strcmp(pdev->name, driver_name)) {
+ VDBG("Wrong device");
+ return -ENODEV;
+ }
+
+ the_udc = udc = kzalloc(sizeof(struct tegra_udc), GFP_KERNEL);
+ if (udc == NULL) {
+ ERR("malloc udc failed\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENXIO;
+ ERR("failed to get platform resources\n");
+ goto err_kfree;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ driver_name)) {
+ ERR("request mem region failed\n");
+ err = -EBUSY;
+ goto err_kfree;
+ }
+
+ udc->regs = ioremap(res->start, resource_size(res));
+ if (!udc->regs) {
+ err = -ENOMEM;
+ ERR("failed to map mem region\n");
+ goto err_rel_mem_region;
+ }
+
+ udc->irq = platform_get_irq(pdev, 0);
+ if (!udc->irq) {
+ err = -ENODEV;
+ ERR("failed to get platform irq resources\n");
+ goto err_iounmap;
+ }
+
+ err = request_irq(udc->irq, tegra_udc_irq, IRQF_SHARED,
+ driver_name, udc);
+ if (err) {
+ ERR("cannot request irq %d err %d\n", udc->irq, err);
+ goto err_iounmap;
+ }
+
+#ifdef IS_NEW_PHY_DRIVER
+ udc->phy = tegra_usb_phy_open(pdev);
+ if (IS_ERR(udc->phy)) {
+ dev_err(&pdev->dev, "failed to open USB phy\n");
+ err = -ENXIO;
+ goto err_irq;
+ }
+
+ err = tegra_usb_phy_power_on(udc->phy);
+ if (err) {
+ dev_err(&pdev->dev, "failed to power on the phy\n");
+ goto err_phy;
+ }
+
+ err = tegra_usb_phy_init(udc->phy);
+ if (err) {
+ dev_err(&pdev->dev, "failed to init the phy\n");
+ goto err_phy;
+ }
+#else
+ /* Initialize USB clocks */
+ fsl_udc_clk_init(pdev);
+#endif
+ spin_lock_init(&udc->lock);
+ udc->stopped = 1;
+ udc->pdev = pdev;
+#ifdef IS_NEW_PHY_DRIVER
+ udc->has_hostpc = tegra_usb_phy_has_hostpc(udc->phy) ? 1 : 0;
+#else
+ #ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ udc->has_hostpc = 0;
+ #else
+ udc->has_hostpc = 1;
+ #endif
+#endif
+
+ platform_set_drvdata(pdev, udc);
+
+ /* Initialize the udc structure including QH members */
+ err = tegra_udc_setup_qh(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup udc QH\n");
+ goto err_phy;
+ }
+
+ /* initialize usb hw reg except for regs for EP,
+ * leave usbintr reg untouched */
+ err = dr_controller_setup(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup udc controller\n");
+ goto err_phy;
+ }
+
+ err = tegra_udc_setup_gadget_dev(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup udc gadget device\n");
+ goto err_phy;
+ }
+
+ err = tegra_udc_ep_setup(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup end points\n");
+ goto err_unregister;
+ }
+
+ /* use dma_pool for TD management */
+ udc->td_pool = dma_pool_create("udc_td", &pdev->dev,
+ sizeof(struct ep_td_struct),
+ DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
+ if (!udc->td_pool) {
+ err = -ENOMEM;
+ goto err_unregister;
+ }
+
+ err = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ if (err)
+ goto err_del_udc;
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ boost_cpufreq_work_flag = 1;
+ ep_queue_request_count = 0;
+ INIT_WORK(&udc->boost_cpufreq_work,
+ tegra_udc_boost_cpu_frequency_work);
+ pm_qos_add_request(&boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
+ PM_QOS_DEFAULT_VALUE);
+#endif
+
+ /* create a work for controlling clocks to the phy if otg is disabled */
+ INIT_WORK(&udc->irq_work, tegra_udc_irq_work);
+ /* create a delayed work for detecting the USB charger */
+ INIT_DELAYED_WORK(&udc->work, tegra_udc_charger_detect_work);
+ INIT_WORK(&udc->charger_work, tegra_udc_set_current_limit_work);
+
+ /* Get the regulator for drawing the vbus current in udc driver */
+ udc->vbus_reg = regulator_get(NULL, "usb_bat_chg");
+ if (IS_ERR(udc->vbus_reg)) {
+ dev_info(&pdev->dev,
+ "usb_bat_chg regulator not registered:"
+ " USB charging will not be enabled\n");
+ udc->vbus_reg = NULL;
+ }
+
+#ifdef CONFIG_USB_OTG_UTILS
+
+#ifdef IS_NEW_PHY_DRIVER
+ if (tegra_usb_phy_otg_supported(udc->phy))
+ udc->transceiver = otg_get_transceiver();
+#else
+ udc->transceiver = otg_get_transceiver();
+#endif
+
+ if (udc->transceiver) {
+ dr_controller_stop(udc);
+ dr_controller_reset(udc);
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_off(udc->phy);
+#else
+ fsl_udc_clk_suspend(false);
+#endif
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ otg_set_peripheral(udc->transceiver, &udc->gadget);
+ }
+#else
+ /* Power down the phy if cable is not connected */
+ if (!vbus_enabled()) {
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_off(udc->phy);
+#else
+ fsl_udc_clk_suspend(false);
+#endif
+ }
+#endif
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+
+err_del_udc:
+ dma_pool_destroy(udc->td_pool);
+
+err_unregister:
+ device_unregister(&udc->gadget.dev);
+
+#ifdef IS_NEW_PHY_DRIVER
+err_phy:
+ tegra_usb_phy_close(udc->phy);
+
+err_irq:
+ free_irq(udc->irq, udc);
+#else
+err_phy:
+#endif
+
+err_iounmap:
+ iounmap(udc->regs);
+
+err_rel_mem_region:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+err_kfree:
+ kfree(udc);
+
+ return err;
+}
+
+/* Driver removal function
+ * Free resources and finish pending transactions
+ */
+static int __exit tegra_udc_remove(struct platform_device *pdev)
+{
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ DECLARE_COMPLETION(done);
+
+ if (!udc)
+ return -ENODEV;
+
+ usb_del_gadget_udc(&udc->gadget);
+ udc->done = &done;
+
+ cancel_delayed_work(&udc->work);
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ cancel_work_sync(&udc->boost_cpufreq_work);
+#endif
+
+ if (udc->vbus_reg)
+ regulator_put(udc->vbus_reg);
+
+ if (udc->transceiver)
+ otg_set_peripheral(udc->transceiver, NULL);
+
+#ifndef IS_NEW_PHY_DRIVER
+ fsl_udc_clk_release();
+#endif
+
+ /* Free allocated memory */
+ dma_free_coherent(&pdev->dev, STATUS_BUFFER_SIZE,
+ udc->status_req->req.buf,
+ udc->status_req->req.dma);
+ kfree(udc->status_req);
+ kfree(udc->eps);
+
+ dma_pool_destroy(udc->td_pool);
+ free_irq(udc->irq, udc);
+ iounmap(udc->regs);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ device_unregister(&udc->gadget.dev);
+ /* free udc --wait for the release() finished */
+ wait_for_completion(&done);
+
+ return 0;
+}
+
+static int tegra_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* if it controller is in otg mode, return */
+ if (udc->transceiver)
+ return 0;
+
+ if (udc->vbus_active) {
+ spin_lock(&udc->lock);
+ /* Reset all internal Queues and inform client driver */
+ reset_queues(udc);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock(&udc->lock);
+ }
+ /* stop the controller and turn off the clocks */
+ dr_controller_stop(udc);
+ if (udc->transceiver)
+ udc->transceiver->state = OTG_STATE_UNDEFINED;
+
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_off(udc->phy);
+#else
+ fsl_udc_clk_suspend(true);
+#endif
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+static int tegra_udc_resume(struct platform_device *pdev)
+{
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+#ifndef IS_NEW_PHY_DRIVER
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ /* Work around to get UTMIP_OTGPD, UTMIP_BIASPD values correctly */
+ fsl_udc_clk_resume(true);
+ fsl_udc_clk_suspend(true);
+#endif
+#endif
+
+ if (udc->transceiver)
+ return 0;
+
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_on(udc->phy);
+#else
+ fsl_udc_clk_resume(true);
+ fsl_udc_clk_resume(true);
+#endif
+ tegra_udc_restart(udc);
+
+ /* Power down the phy if cable is not connected */
+ if (!vbus_enabled(udc)) {
+ udc->vbus_active = 0;
+#ifdef IS_NEW_PHY_DRIVER
+ tegra_usb_phy_power_off(udc->phy);
+#else
+ fsl_udc_clk_suspend(true);
+#endif
+ }
+
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+
+static struct platform_driver tegra_udc_driver = {
+ .remove = __exit_p(tegra_udc_remove),
+ .suspend = tegra_udc_suspend,
+ .resume = tegra_udc_resume,
+ .driver = {
+ .name = (char *)driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init udc_init(void)
+{
+ printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
+ return platform_driver_probe(&tegra_udc_driver, tegra_udc_probe);
+}
+module_init(udc_init);
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&tegra_udc_driver);
+ printk(KERN_WARNING "%s unregistered\n", driver_desc);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tegra-udc");
diff --git a/drivers/usb/gadget/tegra_udc.h b/drivers/usb/gadget/tegra_udc.h
new file mode 100644
index 000000000000..e94543fd98e3
--- /dev/null
+++ b/drivers/usb/gadget/tegra_udc.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Description:
+ * High-speed USB device controller driver.
+ * USB device/endpoint management registers.
+ * The driver is previously named as fsl_udc_core. Based on Freescale driver
+ * code from Li Yang and Jiang Bo.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#ifndef __TEGRA_UDC_H
+#define __TEGRA_UDC_H
+
+#ifdef VERBOSE
+#define VDBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
+ __func__, ## args)
+#else
+#define VDBG(fmt, args...) do {} while (0)
+#endif
+
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra_udc: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+#define ERR(stuff...) pr_err("tegra_udc: " stuff)
+#define WARNING(stuff...) pr_warning("tegra_udc: " stuff)
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define STATUS_BUFFER_SIZE 8
+
+#define USB_MAX_CTRL_PAYLOAD 64
+
+ /* Charger current limit=1800mA, as per the USB charger spec */
+#define USB_CHARGING_CURRENT_LIMIT_MA 1800
+ /* 1 sec wait time for charger detection after vbus is detected */
+#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
+#define BOOST_TRIGGER_SIZE 4096
+
+#define UDC_RESET_TIMEOUT_MS 1000
+#define UDC_RUN_TIMEOUT_MS 1000
+#define UDC_FLUSH_TIMEOUT_MS 1000
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+
+/*
+ * ### pipe direction macro from device view
+ */
+#define USB_RECV 0 /* OUT EP */
+#define USB_SEND 1 /* IN EP */
+
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_REG_OFFSET 0x124
+#define DCCPARAMS_DC 0x00000080
+#define DCCPARAMS_DEN_MASK 0x0000001f
+
+/* USB CMD Register Bit Masks */
+#define USB_CMD_REG_OFFSET ((udc->has_hostpc) ? 0x130 : 0x140)
+#define USB_CMD_RUN_STOP 0x00000001
+#define USB_CMD_CTRL_RESET 0x00000002
+#define USB_CMD_PERIODIC_SCHEDULE_EN 0x00000010
+#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020
+#define USB_CMD_INT_AA_DOORBELL 0x00000040
+#define USB_CMD_ASP 0x00000300
+#define USB_CMD_ASYNC_SCH_PARK_EN 0x00000800
+#define USB_CMD_SUTW 0x00002000
+#define USB_CMD_ATDTW 0x00004000
+#define USB_CMD_ITC 0x00FF0000
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024 0x00000000
+#define USB_CMD_FRAME_SIZE_512 0x00000004
+#define USB_CMD_FRAME_SIZE_256 0x00000008
+#define USB_CMD_FRAME_SIZE_128 0x0000000C
+#define USB_CMD_FRAME_SIZE_64 0x00008000
+#define USB_CMD_FRAME_SIZE_32 0x00008004
+#define USB_CMD_FRAME_SIZE_16 0x00008008
+#define USB_CMD_FRAME_SIZE_8 0x0000800C
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00 0x00000000
+#define USB_CMD_ASP_01 0x00000100
+#define USB_CMD_ASP_10 0x00000200
+#define USB_CMD_ASP_11 0x00000300
+#define USB_CMD_ASP_BIT_POS 8
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD 0x00000000
+#define USB_CMD_ITC_1_MICRO_FRM 0x00010000
+#define USB_CMD_ITC_2_MICRO_FRM 0x00020000
+#define USB_CMD_ITC_4_MICRO_FRM 0x00040000
+#define USB_CMD_ITC_8_MICRO_FRM 0x00080000
+#define USB_CMD_ITC_16_MICRO_FRM 0x00100000
+#define USB_CMD_ITC_32_MICRO_FRM 0x00200000
+#define USB_CMD_ITC_64_MICRO_FRM 0x00400000
+#define USB_CMD_ITC_BIT_POS 16
+
+/* USB STS Register Bit Masks */
+#define USB_STS_REG_OFFSET ((udc->has_hostpc) ? 0x134 : 0x144)
+#define USB_STS_INT 0x00000001
+#define USB_STS_ERR 0x00000002
+#define USB_STS_PORT_CHANGE 0x00000004
+#define USB_STS_FRM_LST_ROLL 0x00000008
+#define USB_STS_SYS_ERR 0x00000010
+#define USB_STS_IAA 0x00000020
+#define USB_STS_RESET 0x00000040
+#define USB_STS_SOF 0x00000080
+#define USB_STS_SUSPEND 0x00000100
+#define USB_STS_HC_HALTED 0x00001000
+#define USB_STS_RCL 0x00002000
+#define USB_STS_PERIODIC_SCHEDULE 0x00004000
+#define USB_STS_ASYNC_SCHEDULE 0x00008000
+
+/* USB INTR Register Bit Masks */
+#define USB_INTR_REG_OFFSET ((udc->has_hostpc) ? 0x138 : 0x148)
+#define USB_INTR_INT_EN 0x00000001
+#define USB_INTR_ERR_INT_EN 0x00000002
+#define USB_INTR_PTC_DETECT_EN 0x00000004
+#define USB_INTR_FRM_LST_ROLL_EN 0x00000008
+#define USB_INTR_SYS_ERR_EN 0x00000010
+#define USB_INTR_ASYN_ADV_EN 0x00000020
+#define USB_INTR_RESET_EN 0x00000040
+#define USB_INTR_SOF_EN 0x00000080
+#define USB_INTR_DEVICE_SUSPEND 0x00000100
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_REG_OFFSET ((udc->has_hostpc) ? 0x13c : 0x14c)
+#define USB_FRINDEX_MASKS 0x3fff
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDR_REG_OFFSET ((udc->has_hostpc) ? 0x144 : 0x154)
+#define USB_DEVICE_ADDRESS_MASK 0xFE000000
+#define USB_DEVICE_ADDRESS_BIT_POS 25
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_REG_OFFSET ((udc->has_hostpc) ? 0x148 : 0x158)
+#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_REG_OFFSET ((udc->has_hostpc) ? 0x174 : 0x184)
+#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001
+#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002
+#define PORTSCX_PORT_ENABLE 0x00000004
+#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008
+#define PORTSCX_OVER_CURRENT_ACT 0x00000010
+#define PORTSCX_OVER_CURRENT_CHG 0x00000020
+#define PORTSCX_PORT_FORCE_RESUME 0x00000040
+#define PORTSCX_PORT_SUSPEND 0x00000080
+#define PORTSCX_PORT_RESET 0x00000100
+#define PORTSCX_LINE_STATUS_BITS 0x00000C00
+#define PORTSCX_PORT_POWER 0x00001000
+#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000
+#define PORTSCX_PORT_TEST_CTRL 0x000F0000
+#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000
+#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000
+#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000
+#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000
+
+/* In tegra3 the following fields have moved to new HOSTPC1_DEVLC reg and
+ * their offsets have changed.
+ * Keeping the name of bit masks same as before (PORTSCX_*) to have
+ * minimum changes to code */
+#define USB_HOSTPCX_DEVLC_REG_OFFSET 0x1b4
+
+#define PORTSCX_PORT_FORCE_FULL_SPEED ((udc->has_hostpc) ? 0x00800000 \
+ : 0x01000000)
+#define PORTSCX_PORT_SPEED_MASK ((udc->has_hostpc) ? 0x06000000 : 0x0C000000)
+#define PORTSCX_PORT_WIDTH ((udc->has_hostpc) ? 0x08000000 : 0x10000000)
+#define PORTSCX_PHY_TYPE_SEL ((udc->has_hostpc) ? 0xE0000000 : 0xC0000000)
+
+/* bits for port speed */
+#define PORTSCX_PORT_SPEED_FULL ((udc->has_hostpc) ? 0x00000000 : 0x00000000)
+#define PORTSCX_PORT_SPEED_LOW ((udc->has_hostpc) ? 0x02000000 : 0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH ((udc->has_hostpc) ? 0x04000000 : 0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF ((udc->has_hostpc) ? 0x06000000 : 0x0C000000)
+#define PORTSCX_SPEED_BIT_POS ((udc->has_hostpc) ? 25 : 26)
+
+/* bits for parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW ((udc->has_hostpc) ? 0x08000000 : 0x10000000)
+#define PORTSCX_PTW_8BIT ((udc->has_hostpc) ? 0x00000000 : 0x00000000)
+#define PORTSCX_PTW_16BIT ((udc->has_hostpc) ? 0x08000000 : 0x10000000)
+
+/* bits for port transceiver select */
+#define PORTSCX_PTS_UTMI ((udc->has_hostpc) ? 0x00000000 : 0x00000000)
+#define PORTSCX_PTS_ULPI ((udc->has_hostpc) ? 0x40000000 : 0x80000000)
+#define PORTSCX_PTS_FSLS ((udc->has_hostpc) ? 0x60000000 : 0xC0000000)
+#define PORTSCX_PTS_BIT_POS ((udc->has_hostpc) ? 29 : 30)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 0x00000000
+#define PORTSCX_LINE_STATUS_JSTATE 0x00000400
+#define PORTSCX_LINE_STATUS_KSTATE 0x00000800
+#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00
+#define PORTSCX_LINE_STATUS_BIT_POS 10
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF 0x00000000
+#define PORTSCX_PIC_AMBER 0x00004000
+#define PORTSCX_PIC_GREEN 0x00008000
+#define PORTSCX_PIC_UNDEF 0x0000C000
+#define PORTSCX_PIC_BIT_POS 14
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE 0x00000000
+#define PORTSCX_PTC_JSTATE 0x00010000
+#define PORTSCX_PTC_KSTATE 0x00020000
+#define PORTSCX_PTC_SEQNAK 0x00030000
+#define PORTSCX_PTC_PACKET 0x00040000
+#define PORTSCX_PTC_FORCE_EN 0x00050000
+#define PORTSCX_PTC_BIT_POS 16
+
+
+/* USB MODE Register Bit Masks */
+#define USB_MODE_REG_OFFSET ((udc->has_hostpc) ? 0x1f8 : 0x1a8)
+#define USB_MODE_CTRL_MODE_IDLE 0x00000000
+#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
+#define USB_MODE_CTRL_MODE_HOST 0x00000003
+#define USB_MODE_CTRL_MODE_RSV 0x00000001
+#define USB_MODE_SETUP_LOCK_OFF 0x00000008
+#define USB_MODE_STREAM_DISABLE 0x00000010
+
+/* Endpoint Setup Status bit masks */
+#define EP_SETUP_STATUS_REG_OFFSET ((udc->has_hostpc) ? 0x208 : 0x1ac)
+#define EP_SETUP_STATUS_MASK 0x0000003F
+#define EP_SETUP_STATUS_EP0 0x00000001
+
+/* Endpoint Prime Register */
+#define EP_PRIME_REG_OFFSET ((udc->has_hostpc) ? 0x20c : 0x1b0)
+
+/* Endpoint Flush Register */
+#define EPFLUSH_REG_OFFSET ((udc->has_hostpc) ? 0x210 : 0x1b4)
+#define EPFLUSH_TX_OFFSET 0x00010000
+#define EPFLUSH_RX_OFFSET 0x00000000
+
+/* Endpoint Status Register */
+#define EP_STATUS_REG_OFFSET ((udc->has_hostpc) ? 0x214 : 0x1b8)
+
+/* Endpoint Complete Register */
+#define EP_COMPLETE_REG_OFFSET ((udc->has_hostpc) ? 0x218 : 0x1bc)
+
+/* Endpoint Control Registers */
+#define EP_CONTROL_REG_OFFSET ((udc->has_hostpc) ? 0x21c : 0x1c0)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE 0x00800000
+#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */
+#define EPCTRL_TX_TYPE 0x000C0000
+#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */
+#define EPCTRL_TX_EP_STALL 0x00010000
+#define EPCTRL_RX_ENABLE 0x00000080
+#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */
+#define EPCTRL_RX_TYPE 0x0000000C
+#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */
+#define EPCTRL_RX_EP_STALL 0x00000001
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_EP_TYPE_CONTROL 0
+#define EPCTRL_EP_TYPE_ISO 1
+#define EPCTRL_EP_TYPE_BULK 2
+#define EPCTRL_EP_TYPE_INTERRUPT 3
+#define EPCTRL_TX_EP_TYPE_SHIFT 18
+#define EPCTRL_RX_EP_TYPE_SHIFT 2
+
+#define VBUS_SENSOR_REG_OFFSET 0x404
+#define VBUS_WAKEUP_REG_OFFSET 0x408
+
+#define USB_SYS_VBUS_ASESSION_INT_EN 0x10000
+#define USB_SYS_VBUS_ASESSION_CHANGED 0x20000
+#define USB_SYS_VBUS_ASESSION 0x40000
+#define USB_SYS_VBUS_WAKEUP_ENABLE 0x40000000
+#define USB_SYS_VBUS_WAKEUP_INT_ENABLE 0x100
+#define USB_SYS_VBUS_WAKEUP_INT_STATUS 0x200
+#define USB_SYS_VBUS_STATUS 0x400
+#define USB_SYS_ID_PIN_STATUS 0x4
+
+
+/* Endpoint Queue Head Bit Masks */
+#define EP_QUEUE_HEAD_MULT_POS 30
+#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
+#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
+#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
+#define EP_QUEUE_HEAD_IOS 0x00008000
+#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
+#define EP_QUEUE_HEAD_IOC 0x00008000
+#define EP_QUEUE_HEAD_MULTO 0x00000C00
+#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
+#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
+#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
+#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
+#define EP_QUEUE_FRINDEX_MASK 0x000007FF
+#define EP_MAX_LENGTH_TRANSFER 0x4000
+
+
+
+/* Endpoint Transfer Descriptor bit Masks */
+#define DTD_NEXT_TERMINATE 0x00000001
+#define DTD_IOC 0x00008000
+#define DTD_STATUS_ACTIVE 0x00000080
+#define DTD_STATUS_HALTED 0x00000040
+#define DTD_STATUS_DATA_BUFF_ERR 0x00000020
+#define DTD_STATUS_TRANSACTION_ERR 0x00000008
+#define DTD_RESERVED_FIELDS 0x80007300
+#define DTD_ADDR_MASK 0xFFFFFFE0
+#define DTD_PACKET_SIZE 0x7FFF0000
+#define DTD_LENGTH_BIT_POS 16
+#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
+ DTD_STATUS_DATA_BUFF_ERR | \
+ DTD_STATUS_TRANSACTION_ERR)
+/* Alignment requirements; must be a power of two */
+#define DTD_ALIGNMENT 0x80
+#define QH_ALIGNMENT 2048
+#define QH_OFFSET 0x1000
+
+/* Controller dma boundary */
+#define UDC_DMA_BOUNDARY 0x1000
+
+#define REQ_UNCOMPLETE 1
+
+#define EP_DIR_IN 1
+#define EP_DIR_OUT 0
+
+/*
+ * Endpoint Queue Head data struct
+ * Rem: all the variables of qh are LittleEndian Mode
+ * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
+ */
+struct ep_queue_head {
+ u32 max_pkt_length; /* Mult(31-30), Zlt(29), Max Pkt len and IOS(15) */
+ u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */
+ u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */
+ u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */
+ u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */
+ u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */
+ u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */
+ u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */
+ u32 res1;
+ u8 setup_buffer[8]; /* Setup data 8 bytes */
+ u32 res2[4];
+};
+
+/* Endpoint Transfer Descriptor data struct */
+/* Rem: all the variables of td are LittleEndian Mode */
+struct ep_td_struct {
+ u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set
+ indicate invalid */
+ u32 size_ioc_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 */
+ u32 buff_ptr1; /* Buffer pointer Page 1 */
+ u32 buff_ptr2; /* Buffer pointer Page 2 */
+ u32 buff_ptr3; /* Buffer pointer Page 3 */
+ u32 buff_ptr4; /* Buffer pointer Page 4 */
+ u32 res;
+ /* 32 bytes */
+ dma_addr_t td_dma; /* dma address for this td */
+ /* virtual address of next td specified in next_td_ptr */
+ struct ep_td_struct *next_td_virt;
+};
+
+
+struct tegra_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* ep_queue() func will add
+ a request->queue into a udc_ep->queue 'd tail */
+ struct tegra_ep *ep;
+ unsigned mapped:1;
+
+ struct ep_td_struct *head, *tail; /* For dTD List
+ cpu endian Virtual addr */
+ unsigned int dtd_count;
+};
+
+struct tegra_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct tegra_udc *udc;
+ struct ep_queue_head *qh;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_gadget *gadget;
+
+ char name[14];
+ unsigned stopped:1;
+};
+
+struct tegra_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct completion *done; /* to make sure release() is done */
+ struct tegra_ep *eps;
+ struct platform_device *pdev;
+ struct tegra_usb_phy *phy;
+ struct usb_ctrlrequest local_setup_buff;
+ struct otg_transceiver *transceiver;
+ struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
+ struct tegra_req *status_req; /* ep0 status request */
+ struct dma_pool *td_pool; /* dma pool for DTD */
+ struct delayed_work work; /* delayed work for charger detection */
+ struct regulator *vbus_reg; /* regulator for drawing VBUS */
+ /* work for setting regulator current limit */
+ struct work_struct charger_work;
+ /* work for boosting cpu frequency */
+ struct work_struct boost_cpufreq_work;
+ /* irq work for controlling the usb power */
+ struct work_struct irq_work;
+ void __iomem *regs;
+ size_t ep_qh_size; /* size after alignment adjustment*/
+ dma_addr_t ep_qh_dma; /* dma address of QH */
+ unsigned int max_ep;
+ unsigned int irq;
+ u32 max_pipes; /* Device max pipes */
+ u32 resume_state; /* USB state to resume */
+ u32 usb_state; /* USB current state */
+ u32 ep0_state; /* Endpoint zero state */
+ u32 ep0_dir; /* Endpoint zero direction: USB_DIR_IN/USB_DIR_OUT */
+ u8 device_address; /* Device USB address */
+ u32 current_limit;
+ spinlock_t lock;
+ unsigned softconnect:1;
+ unsigned vbus_active:1;
+ unsigned stopped:1;
+ unsigned remote_wakeup:1;
+ unsigned selfpowered:1;
+ bool has_hostpc;
+};
+
+
+#endif /* __TEGRA_UDC_H */
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 05ba47214361..df5ad21f2379 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
static ssize_t usb_udc_srp_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
- struct usb_udc *udc = dev_get_drvdata(dev);
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
if (sysfs_streq(buf, "1"))
usb_gadget_wakeup(udc->gadget);
@@ -356,7 +356,7 @@ static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
static ssize_t usb_udc_softconn_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
- struct usb_udc *udc = dev_get_drvdata(dev);
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
if (sysfs_streq(buf, "connect")) {
usb_gadget_connect(udc->gadget);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index bb86dfa47e7d..4e7277b2b889 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -2,7 +2,7 @@
* EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2009 - 2011 NVIDIA Corporation
+ * Copyright (C) 2009 - 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 as published by the
@@ -578,7 +578,6 @@ static int tegra_usb_suspend(struct usb_hcd *hcd, bool is_dpd)
static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- struct usb_device *udev = hcd->self.root_hub;
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_regs __iomem *hw = ehci->regs;
unsigned long val;
@@ -939,6 +938,22 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
return ret;
ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+
+ /* control packets over dma */
+ if (urb->setup_dma)
+ dma_sync_single_for_device(hcd->self.controller,
+ urb->setup_dma, sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+
+ /* urb buffers over dma */
+ if (urb->transfer_dma) {
+ enum dma_data_direction dir;
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ dma_sync_single_for_device(hcd->self.controller,
+ urb->transfer_dma, urb->transfer_buffer_length, dir);
+ }
+
if (ret)
free_dma_aligned_buffer(urb);
@@ -947,6 +962,25 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
+ struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
+
+ /* Fence read for coherency of AHB master intiated writes */
+ if (tegra->phy->instance == 0)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+ else if (tegra->phy->instance == 1)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
+ else if (tegra->phy->instance == 2)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
+
+ if (urb->transfer_dma) {
+ enum dma_data_direction dir;
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ if (dir == DMA_FROM_DEVICE)
+ dma_sync_single_for_cpu(hcd->self.controller,
+ urb->transfer_dma, urb->transfer_buffer_length,
+ DMA_FROM_DEVICE);
+ }
+
usb_hcd_unmap_urb_for_dma(hcd, urb);
free_dma_aligned_buffer(urb);
}
@@ -1046,31 +1080,32 @@ static const struct hc_driver tegra_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Tegra EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
-
.flags = HCD_USB2 | HCD_MEMORY,
- .reset = tegra_ehci_setup,
- .irq = tegra_ehci_irq,
-
+ /* standard ehci functions */
.start = ehci_run,
.stop = ehci_stop,
- .shutdown = tegra_ehci_shutdown,
- .urb_enqueue = tegra_ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
- .map_urb_for_dma = tegra_ehci_map_urb_for_dma,
- .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
- .hub_control = tegra_ehci_hub_control,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ /* modified ehci functions for tegra */
+ .reset = tegra_ehci_setup,
+ .irq = tegra_ehci_irq,
+ .shutdown = tegra_ehci_shutdown,
+ .map_urb_for_dma = tegra_ehci_map_urb_for_dma,
+ .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
+ .hub_control = tegra_ehci_hub_control,
+ .urb_enqueue = tegra_ehci_urb_enqueue,
#ifdef CONFIG_PM
.bus_suspend = tegra_ehci_bus_suspend,
.bus_resume = tegra_ehci_bus_resume,
#endif
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
};
static int tegra_ehci_probe(struct platform_device *pdev)
@@ -1243,11 +1278,10 @@ fail_hcd:
}
#ifdef CONFIG_PM
-static int tegra_ehci_resume(struct platform_device *pdev)
+static int tegra_ehci_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
- int ret;
mutex_lock(&tegra->tegra_ehci_hcd_mutex);
if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
@@ -1260,13 +1294,31 @@ static int tegra_ehci_resume(struct platform_device *pdev)
if (tegra->default_enable)
clk_enable(tegra->clk);
+ mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ return 0;
+}
+
+static int tegra_ehci_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
+ int ret;
+
+ mutex_lock(&tegra->tegra_ehci_hcd_mutex);
+ if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
+ mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ return 0;
+ }
+
ret = tegra_usb_resume(hcd, true);
mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
return ret;
}
-static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
+static int tegra_ehci_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
int ret;
@@ -1304,6 +1356,13 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
return ret;
}
+
+static struct dev_pm_ops tegra_ehci_dev_pm_ops = {
+ .suspend = tegra_ehci_suspend,
+ .resume = tegra_ehci_resume,
+ .resume_noirq = tegra_ehci_resume_noirq,
+};
+
#endif
static int tegra_ehci_remove(struct platform_device *pdev)
@@ -1363,12 +1422,11 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
static struct platform_driver tegra_ehci_driver = {
.probe = tegra_ehci_probe,
.remove = tegra_ehci_remove,
-#ifdef CONFIG_PM
- .suspend = tegra_ehci_suspend,
- .resume = tegra_ehci_resume,
-#endif
.shutdown = tegra_ehci_hcd_shutdown,
.driver = {
.name = "tegra-ehci",
+#ifdef CONFIG_PM
+ .pm = &tegra_ehci_dev_pm_ops,
+#endif
}
};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index e897262c6a60..509934ceb4a9 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -762,7 +762,7 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
* descriptor to memory.
* */
#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
-static inline void ehci_sync_mem()
+static inline void ehci_sync_mem(void)
{
mb();
}
diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c
index 4c04e6e183f1..d95d238fd9d6 100644
--- a/drivers/usb/otg/tegra-otg.c
+++ b/drivers/usb/otg/tegra-otg.c
@@ -42,10 +42,18 @@
#define USB_VBUS_INT_STATUS (1 << 9)
#define USB_VBUS_STATUS (1 << 10)
#define USB_INTS (USB_VBUS_INT_STATUS | USB_ID_INT_STATUS)
+#define USB_INT_EN (USB_VBUS_INT_EN | USB_ID_INT_EN | \
+ USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN)
typedef void (*callback_t)(enum usb_otg_state to,
enum usb_otg_state from, void *args);
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra-otg: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
struct tegra_otg_data {
struct otg_transceiver otg;
unsigned long int_status;
@@ -56,11 +64,11 @@ struct tegra_otg_data {
struct platform_device *pdev;
struct work_struct work;
unsigned int intr_reg_data;
- bool detect_vbus;
bool clk_enabled;
callback_t charger_cb;
void *charger_cb_data;
+ bool interrupt_mode;
};
static struct tegra_otg_data *tegra_clone;
@@ -106,6 +114,24 @@ static const char *tegra_state_name(enum usb_otg_state state)
}
}
+static unsigned long enable_interrupt(struct tegra_otg_data *tegra, bool en)
+{
+ unsigned long val;
+
+ clk_enable(tegra->clk);
+ val = otg_readl(tegra, USB_PHY_WAKEUP);
+ if (en)
+ val |= USB_INT_EN;
+ else
+ val &= ~USB_INT_EN;
+ otg_writel(tegra, val, USB_PHY_WAKEUP);
+ /* Add delay to make sure register is updated */
+ udelay(1);
+ clk_disable(tegra->clk);
+
+ return val;
+}
+
static struct platform_device *
tegra_usb_otg_host_register(struct platform_device *ehci_device,
struct tegra_ehci_platform_data *pdata)
@@ -157,19 +183,27 @@ static void tegra_usb_otg_host_unregister(struct platform_device *pdev)
void tegra_start_host(struct tegra_otg_data *tegra)
{
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
struct tegra_otg_platform_data *pdata = tegra->otg.dev->platform_data;
if (!tegra->pdev) {
tegra->pdev = tegra_usb_otg_host_register(pdata->ehci_device,
pdata->ehci_pdata);
}
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
}
void tegra_stop_host(struct tegra_otg_data *tegra)
{
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
if (tegra->pdev) {
tegra_usb_otg_host_unregister(tegra->pdev);
tegra->pdev = NULL;
}
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
}
int register_otg_callback(callback_t cb, void *args)
@@ -182,72 +216,80 @@ int register_otg_callback(callback_t cb, void *args)
}
EXPORT_SYMBOL_GPL(register_otg_callback);
-static void irq_work(struct work_struct *work)
+static void tegra_change_otg_state(struct tegra_otg_data *tegra,
+ enum usb_otg_state to)
{
- struct tegra_otg_data *tegra =
- container_of(work, struct tegra_otg_data, work);
struct otg_transceiver *otg = &tegra->otg;
enum usb_otg_state from = otg->state;
- enum usb_otg_state to = OTG_STATE_UNDEFINED;
- unsigned long flags;
- unsigned long status;
- if (tegra->detect_vbus) {
- tegra->detect_vbus = false;
- tegra_otg_enable_clk();
+ if(!tegra->interrupt_mode){
+ DBG("OTG: Vbus detection is disabled");
return;
}
- clk_enable(tegra->clk);
-
- spin_lock_irqsave(&tegra->lock, flags);
-
- status = tegra->int_status;
-
- if (tegra->int_status & USB_ID_INT_STATUS) {
- if (status & USB_ID_STATUS) {
- if ((status & USB_VBUS_STATUS) && (from != OTG_STATE_A_HOST))
- to = OTG_STATE_B_PERIPHERAL;
- else
- to = OTG_STATE_A_SUSPEND;
- }
- else
- to = OTG_STATE_A_HOST;
- }
- if (from != OTG_STATE_A_HOST) {
- if (tegra->int_status & USB_VBUS_INT_STATUS) {
- if (status & USB_VBUS_STATUS)
- to = OTG_STATE_B_PERIPHERAL;
- else
- to = OTG_STATE_A_SUSPEND;
- }
- }
- spin_unlock_irqrestore(&tegra->lock, flags);
+ DBG("%s(%d) requested otg state %s-->%s\n", __func__,
+ __LINE__, tegra_state_name(from), tegra_state_name(to));
- if (to != OTG_STATE_UNDEFINED) {
+ if (to != OTG_STATE_UNDEFINED && from != to) {
otg->state = to;
-
dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from),
tegra_state_name(to));
if (tegra->charger_cb)
tegra->charger_cb(to, from, tegra->charger_cb_data);
- if (to == OTG_STATE_A_SUSPEND) {
- if (from == OTG_STATE_A_HOST)
+ if (from == OTG_STATE_A_SUSPEND) {
+ if (to == OTG_STATE_B_PERIPHERAL && otg->gadget)
+ usb_gadget_vbus_connect(otg->gadget);
+ else if (to == OTG_STATE_A_HOST)
+ tegra_start_host(tegra);
+ } else if (from == OTG_STATE_A_HOST) {
+ if (to == OTG_STATE_A_SUSPEND)
tegra_stop_host(tegra);
- else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget)
+ } else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) {
+ if (to == OTG_STATE_A_SUSPEND)
usb_gadget_vbus_disconnect(otg->gadget);
- } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) {
- if (from == OTG_STATE_A_SUSPEND)
- usb_gadget_vbus_connect(otg->gadget);
- } else if (to == OTG_STATE_A_HOST) {
- if (from == OTG_STATE_A_SUSPEND)
- tegra_start_host(tegra);
}
}
+}
+static void irq_work(struct work_struct *work)
+{
+ struct tegra_otg_data *tegra =
+ container_of(work, struct tegra_otg_data, work);
+ struct otg_transceiver *otg = &tegra->otg;
+ enum usb_otg_state from = otg->state;
+ enum usb_otg_state to = OTG_STATE_UNDEFINED;
+ unsigned long flags;
+ unsigned long status;
+
+ clk_enable(tegra->clk);
+
+ spin_lock_irqsave(&tegra->lock, flags);
+
+ status = tegra->int_status;
+ /* Debug prints */
+ DBG("%s(%d) status = 0x%x\n", __func__, __LINE__, status);
+ if ((status & USB_ID_INT_STATUS) &&
+ (status & USB_VBUS_INT_STATUS))
+ DBG("%s(%d) got vbus & id interrupt\n", __func__, __LINE__);
+ else {
+ if (status & USB_ID_INT_STATUS)
+ DBG("%s(%d) got id interrupt\n", __func__, __LINE__);
+ if (status & USB_VBUS_INT_STATUS)
+ DBG("%s(%d) got vbus interrupt\n", __func__, __LINE__);
+ }
+
+ if (!(status & USB_ID_STATUS))
+ to = OTG_STATE_A_HOST;
+ else if (status & USB_VBUS_STATUS && from != OTG_STATE_A_HOST)
+ to = OTG_STATE_B_PERIPHERAL;
+ else
+ to = OTG_STATE_A_SUSPEND;
+
+ spin_unlock_irqrestore(&tegra->lock, flags);
+ tegra_change_otg_state(tegra, to);
clk_disable(tegra->clk);
tegra_otg_disable_clk();
}
@@ -262,10 +304,10 @@ static irqreturn_t tegra_otg_irq(int irq, void *data)
val = otg_readl(tegra, USB_PHY_WAKEUP);
if (val & (USB_VBUS_INT_EN | USB_ID_INT_EN)) {
+ DBG("%s(%d) PHY_WAKEUP = 0x%x\n", __func__, __LINE__, val);
otg_writel(tegra, val, USB_PHY_WAKEUP);
if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
tegra->int_status = val;
- tegra->detect_vbus = false;
schedule_work(&tegra->work);
}
}
@@ -277,8 +319,7 @@ static irqreturn_t tegra_otg_irq(int irq, void *data)
void tegra_otg_check_vbus_detection(void)
{
- tegra_clone->detect_vbus = true;
- schedule_work(&tegra_clone->work);
+ tegra_otg_enable_clk();
}
EXPORT_SYMBOL(tegra_otg_check_vbus_detection);
@@ -287,33 +328,26 @@ static int tegra_otg_set_peripheral(struct otg_transceiver *otg,
{
struct tegra_otg_data *tegra;
unsigned long val;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
tegra = container_of(otg, struct tegra_otg_data, otg);
otg->gadget = gadget;
- clk_enable(tegra->clk);
- val = otg_readl(tegra, USB_PHY_WAKEUP);
- val |= (USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN);
- val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
- otg_writel(tegra, val, USB_PHY_WAKEUP);
- /* Add delay to make sure register is updated */
- udelay(1);
- clk_disable(tegra->clk);
+ val = enable_interrupt(tegra, true);
- if ((val & USB_ID_STATUS) && (val & USB_VBUS_STATUS)) {
+ if ((val & USB_ID_STATUS) && (val & USB_VBUS_STATUS))
val |= USB_VBUS_INT_STATUS;
- } else if (!(val & USB_ID_STATUS)) {
+ else if (!(val & USB_ID_STATUS))
val |= USB_ID_INT_STATUS;
- } else {
+ else
val &= ~(USB_ID_INT_STATUS | USB_VBUS_INT_STATUS);
- }
if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
tegra->int_status = val;
- tegra->detect_vbus = false;
schedule_work (&tegra->work);
}
+ DBG("%s(%d) END\n", __func__, __LINE__);
return 0;
}
@@ -322,6 +356,7 @@ static int tegra_otg_set_host(struct otg_transceiver *otg,
{
struct tegra_otg_data *tegra;
unsigned long val;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
tegra = container_of(otg, struct tegra_otg_data, otg);
otg->host = host;
@@ -334,6 +369,7 @@ static int tegra_otg_set_host(struct otg_transceiver *otg,
otg_writel(tegra, val, USB_PHY_WAKEUP);
clk_disable(tegra->clk);
+ DBG("%s(%d) END\n", __func__, __LINE__);
return 0;
}
@@ -347,6 +383,46 @@ static int tegra_otg_set_suspend(struct otg_transceiver *otg, int suspend)
return 0;
}
+static ssize_t show_host_en(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+
+ *buf = tegra->interrupt_mode ? '0': '1';
+ strcat(buf, "\n");
+ return strlen(buf);
+}
+
+static ssize_t store_host_en(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ unsigned long host;
+ int err;
+
+ err = kstrtoul(buf, 10, &host);
+ if (err < 0) {
+ return err;
+ }
+
+ if (host) {
+ enable_interrupt(tegra, false);
+ tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND);
+ tegra_change_otg_state(tegra, OTG_STATE_A_HOST);
+ tegra->interrupt_mode = false;
+ } else {
+ tegra->interrupt_mode = true;
+ tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND);
+ enable_interrupt(tegra, true);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(enable_host, 0644, show_host_en, store_host_en);
+
static int tegra_otg_probe(struct platform_device *pdev)
{
struct tegra_otg_data *tegra;
@@ -373,6 +449,7 @@ static int tegra_otg_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tegra);
tegra_clone = tegra;
tegra->clk_enabled = false;
+ tegra->interrupt_mode = true;
tegra->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(tegra->clk)) {
@@ -424,6 +501,13 @@ static int tegra_otg_probe(struct platform_device *pdev)
if (!ehci_pdata->default_enable)
clk_disable(tegra->clk);
dev_info(&pdev->dev, "otg transceiver registered\n");
+
+ err = device_create_file(&pdev->dev, &dev_attr_enable_host);
+ if (err) {
+ dev_warn(&pdev->dev, "Can't register sysfs attribute\n");
+ goto err_irq;
+ }
+
return 0;
err_irq:
@@ -461,17 +545,21 @@ static int tegra_otg_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev);
struct otg_transceiver *otg = &tegra_otg->otg;
- enum usb_otg_state from = otg->state;
- /* store the interupt enable for cable ID and VBUS */
+ int val;
+ DBG("%s(%d) BEGIN state : %s\n", __func__, __LINE__,
+ tegra_state_name(otg->state));
+
clk_enable(tegra_otg->clk);
- tegra_otg->intr_reg_data = readl(tegra_otg->regs + USB_PHY_WAKEUP);
- writel(0, (tegra_otg->regs + USB_PHY_WAKEUP));
+ val = readl(tegra_otg->regs + USB_PHY_WAKEUP);
+ val &= ~USB_INT_EN;
+ writel(val, tegra_otg->regs + USB_PHY_WAKEUP);
clk_disable(tegra_otg->clk);
- if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) {
- usb_gadget_vbus_disconnect(otg->gadget);
- otg->state = OTG_STATE_A_SUSPEND;
- }
+ /* suspend peripheral mode, host mode is taken care by host driver */
+ if (otg->state == OTG_STATE_B_PERIPHERAL)
+ tegra_change_otg_state(tegra_otg, OTG_STATE_A_SUSPEND);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
tegra_otg_disable_clk();
return 0;
}
@@ -480,34 +568,35 @@ static void tegra_otg_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev);
+ struct otg_transceiver *otg = &tegra_otg->otg;
+
int val;
unsigned long flags;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
- tegra_otg_enable_clk();
-
- /* Following delay is intentional.
- * It is placed here after observing system hang.
- * Root cause is not confirmed.
- */
- msleep(1);
- /* restore the interupt enable for cable ID and VBUS */
+ /* Clear pending interrupts */
clk_enable(tegra_otg->clk);
- writel(tegra_otg->intr_reg_data, (tegra_otg->regs + USB_PHY_WAKEUP));
val = readl(tegra_otg->regs + USB_PHY_WAKEUP);
+ writel(val, tegra_otg->regs + USB_PHY_WAKEUP);
+ DBG("%s(%d) PHY WAKEUP register : 0x%x\n", __func__, __LINE__, val);
clk_disable(tegra_otg->clk);
- /* A device might be connected while CPU is in sleep mode. In this case no interrupt
- * will be triggered
- * force irq_work to recheck connected devices
- */
- if (!(val & USB_ID_STATUS)) {
- spin_lock_irqsave(&tegra_otg->lock, flags);
- tegra_otg->int_status = (val | USB_ID_INT_STATUS );
- schedule_work(&tegra_otg->work);
- spin_unlock_irqrestore(&tegra_otg->lock, flags);
- }
+ /* Handle if host cable is replaced with device during suspend state */
+ if (otg->state == OTG_STATE_A_HOST && (val & USB_ID_STATUS))
+ tegra_change_otg_state(tegra_otg, OTG_STATE_A_SUSPEND);
+
+ /* Enable interrupt and call work to set to appropriate state */
+ spin_lock_irqsave(&tegra_otg->lock, flags);
+ tegra_otg->int_status = (val | USB_INT_EN);
+ spin_unlock_irqrestore(&tegra_otg->lock, flags);
+ irq_work(&tegra_otg->work);
- return;
+ clk_enable(tegra_otg->clk);
+ val = readl(tegra_otg->regs + USB_PHY_WAKEUP);
+ val |= USB_INT_EN;
+ writel(val, tegra_otg->regs + USB_PHY_WAKEUP);
+ clk_disable(tegra_otg->clk);
+ DBG("%s(%d) END\n", __func__, __LINE__);
}
static const struct dev_pm_ops tegra_otg_pm_ops = {
diff --git a/drivers/usb/serial/baseband_usb_chr.c b/drivers/usb/serial/baseband_usb_chr.c
index 6d691a40312d..cad33d5b6f49 100644
--- a/drivers/usb/serial/baseband_usb_chr.c
+++ b/drivers/usb/serial/baseband_usb_chr.c
@@ -3,7 +3,7 @@
*
* USB character driver to communicate with baseband modems.
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * 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 as published by
@@ -33,8 +33,9 @@
#include <linux/errno.h>
#include <linux/usb.h>
#include <linux/workqueue.h>
-#include <asm/ioctls.h>
#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <asm/ioctls.h>
#include "baseband_usb_chr.h"
MODULE_LICENSE("GPL");
@@ -51,7 +52,9 @@ module_param(baseband_usb_chr_intf, ulong, 0644);
MODULE_PARM_DESC(baseband_usb_chr_intf, "baseband (usb chr) - USB interface");
static struct baseband_usb *baseband_usb_chr;
+static struct usb_interface *probe_usb_intf;
static bool usb_device_connection;
+static struct workqueue_struct *chr_ipc_wq;
static atomic_t g_rx_count = ATOMIC_INIT(0);
@@ -119,7 +122,7 @@ static size_t peek_ipc_tx_bufsiz(struct baseband_ipc *ipc,
/* check input */
if (!ipc) {
- pr_err("!ipc\n");
+ pr_err("%s: !ipc\n", __func__);
return 0;
}
@@ -159,7 +162,7 @@ static size_t get_ipc_tx_buf(struct baseband_ipc *ipc,
/* check input */
if (!ipc || !buf) {
- pr_err("!ipc || !buf\n");
+ pr_err("%s: !ipc || !buf\n", __func__);
return 0;
}
if (!bufsiz)
@@ -221,12 +224,13 @@ static size_t put_ipc_rx_buf(struct baseband_ipc *ipc,
{
struct baseband_ipc_buf *ipc_buf, *ipc_buf_next;
size_t rx_bufsiz;
+ int ret;
pr_debug("put_ipc_rx_buf\n");
/* check input */
if (!ipc || !buf) {
- pr_err("!ipc || !buf\n");
+ pr_err("%s: !ipc || !buf\n", __func__);
return 0;
}
if (!bufsiz)
@@ -277,8 +281,13 @@ retry:
/* wait for rx free buffer available */
if (!rx_bufsiz) {
- if (wait_event_interruptible(ipc->rx_free.wait,
- !list_empty(&ipc->rx_free.buf))) {
+ ret = wait_event_interruptible_timeout(ipc->rx_free.wait,
+ !list_empty(&ipc->rx_free.buf), HZ*2);
+ if (ret == 0) {
+ pr_err("%s timeout occured no wait\n", __func__);
+ return -ETIMEDOUT;
+ }
+ if (ret == -ERESTARTSYS) {
pr_err("put_ipc_rx_buf - "
"interrupted wait\n");
return -ERESTARTSYS;
@@ -299,8 +308,8 @@ static ssize_t baseband_ipc_file_read(struct baseband_ipc *ipc,
pr_debug("baseband_ipc_file_read\n");
/* check input */
- if (!ipc) {
- pr_err("!ipc\n");
+ if (!ipc || !buf) {
+ pr_err("%s: !ipc || !buf\n", __func__);
return -EIO;
}
@@ -384,11 +393,19 @@ static ssize_t baseband_ipc_file_write(struct baseband_ipc *ipc,
pr_debug("baseband_ipc_file_write\n");
/* check input */
- if (!ipc) {
- pr_err("!ipc\n");
+ if (!ipc || !buf) {
+ pr_err("%s: !ipc || !buf\n", __func__);
return -EIO;
}
+ /* do not accept write if previous tx not finished */
+ if (peek_ipc_tx_bufsiz(ipc, USB_CHR_TX_BUFSIZ) != 0) {
+ pr_info("%s: not accepting write of %u bytes"
+ " - previous tx not finished\n",
+ __func__, count);
+ return 0;
+ }
+
/* acquire tx buffer semaphores */
retry:
if (down_interruptible(&ipc->buf_sem)) {
@@ -473,12 +490,10 @@ static void baseband_ipc_close(struct baseband_ipc *ipc)
if (!ipc)
return;
- /* destroy work queue */
+ /* cancel work queue */
if (ipc->workqueue) {
pr_debug("destroy workqueue {\n");
cancel_work_sync(&ipc->work);
- destroy_workqueue(ipc->workqueue);
- ipc->workqueue = (struct workqueue_struct *) 0;
pr_debug("destroy workqueue }\n");
}
memset(&ipc->work, 0, sizeof(ipc->work));
@@ -496,26 +511,26 @@ static void baseband_ipc_close(struct baseband_ipc *ipc)
ipc->ipc_rx = (unsigned char *) 0;
list_for_each_entry_safe(ipc_buf, ipc_buf_next, &ipc->tx_free.buf, list)
{
- kfree(ipc_buf);
+ vfree(ipc_buf);
}
list_for_each_entry_safe(ipc_buf, ipc_buf_next, &ipc->rx_free.buf, list)
{
- kfree(ipc_buf);
+ vfree(ipc_buf);
}
list_for_each_entry_safe(ipc_buf, ipc_buf_next, &ipc->tx.buf, list)
{
- kfree(ipc_buf);
+ vfree(ipc_buf);
}
list_for_each_entry_safe(ipc_buf, ipc_buf_next, &ipc->rx.buf, list)
{
- kfree(ipc_buf);
+ vfree(ipc_buf);
}
/* destroy semaphores */
memset(&ipc->buf_sem, 0, sizeof(ipc->buf_sem));
/* free baseband ipc structure */
- kfree(ipc);
+ vfree(ipc);
pr_debug("baseband_ipc_close }\n");
}
@@ -531,10 +546,11 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
pr_debug("baseband_ipc_open {\n");
/* allocate baseband ipc structure */
- ipc = kzalloc(sizeof(struct baseband_ipc), GFP_KERNEL);
+ ipc = vmalloc(sizeof(struct baseband_ipc));
if (!ipc)
return (struct baseband_ipc *) 0;
+ memset(ipc, 0 , sizeof(struct baseband_ipc));
/* create semaphores */
sema_init(&ipc->buf_sem, 1);
@@ -545,7 +561,7 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
INIT_LIST_HEAD(&ipc->tx_free.buf);
for (i = 0; i < BASEBAND_IPC_NUM_RX_BUF; i++) {
ipc_buf = (struct baseband_ipc_buf *)
- kzalloc(sizeof(struct baseband_ipc_buf), GFP_KERNEL);
+ vmalloc(sizeof(struct baseband_ipc_buf));
if (!ipc_buf) {
pr_err("cannot allocate baseband ipc rx buffer #%d\n",
i);
@@ -558,7 +574,7 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
}
for (i = 0; i < BASEBAND_IPC_NUM_TX_BUF; i++) {
ipc_buf = (struct baseband_ipc_buf *)
- kzalloc(sizeof(struct baseband_ipc_buf), GFP_KERNEL);
+ vmalloc(sizeof(struct baseband_ipc_buf));
if (!ipc_buf) {
pr_err("cannot allocate baseband ipc tx buffer #%d\n",
i);
@@ -569,8 +585,18 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
ipc_buf);
list_add_tail(&ipc_buf->list, &ipc->tx_free.buf);
}
- ipc->ipc_rx = (unsigned char *) 0;
- ipc->ipc_tx = (unsigned char *) 0;
+ ipc->ipc_rx = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+ if (!ipc->ipc_rx) {
+ pr_err("baseband_ipc_open - "
+ "cannot allocate ipc->ipc_rx\n");
+ goto error_exit;
+ }
+ ipc->ipc_tx = kmalloc(USB_CHR_TX_BUFSIZ, GFP_KERNEL);
+ if (!ipc->ipc_tx) {
+ pr_err("baseband_ipc_open - "
+ "cannot allocate ipc->ipc_tx\n");
+ goto error_exit;
+ }
/* create wait queues */
init_waitqueue_head(&ipc->rx.wait);
@@ -578,11 +604,11 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
init_waitqueue_head(&ipc->rx_free.wait);
init_waitqueue_head(&ipc->tx_free.wait);
- /* create work queue */
- ipc->workqueue = create_singlethread_workqueue
- ("baseband_usb_chr_ipc_workqueue");
- if (!ipc->workqueue) {
- pr_err("cannot create workqueue\n");
+ /* init work queue */
+ if (chr_ipc_wq)
+ ipc->workqueue = chr_ipc_wq;
+ else {
+ pr_err("%s: no workqueue found\n", __func__);
goto error_exit;
}
if (work_func)
@@ -608,6 +634,28 @@ static void baseband_usb_chr_rx_urb_comp(struct urb *urb)
pr_debug("baseband_usb_chr_rx_urb_comp { urb %p\n", urb);
+ /* check input */
+ if (!usb) {
+ pr_err("%s: !usb\n", __func__);
+ return;
+ }
+ if (!usb->ipc) {
+ pr_err("%s: !usb->ipc\n", __func__);
+ return;
+ }
+ if (!usb->ipc->workqueue) {
+ pr_err("%s: !usb->ipc->rx_work\n", __func__);
+ return;
+ }
+
+ switch (urb->status) {
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EPROTO:
+ pr_info("%s: link down\n", __func__);
+ return;
+ }
+
/* queue rx urb completion work */
queue_work(usb->ipc->workqueue, &usb->ipc->rx_work);
@@ -622,29 +670,19 @@ static int baseband_usb_chr_rx_urb_submit(struct baseband_usb *usb)
pr_debug("baseband_usb_chr_rx_urb_submit { usb %p\n", usb);
+ /* check input */
if (!usb_device_connection) {
- pr_err("!!no usb device conenction!!!!!\n");
+ pr_err("%s: no usb device connection\n", __func__);
return -1;
}
-
- /* check input */
- if (usb->usb.rx_urb) {
- pr_err("previous urb still active\n");
+ if (!usb->usb.rx_urb) {
+ pr_err("%s: no rx urb!\n", __func__);
return -1;
}
- /* allocate rx urb */
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb) {
- pr_err("usb_alloc_urb() failed\n");
- return -ENOMEM;
- }
- buf = kzalloc(USB_CHR_RX_BUFSIZ, GFP_ATOMIC);
- if (!buf) {
- pr_err("usb buffer kzalloc() failed\n");
- usb_free_urb(urb);
- return -ENOMEM;
- }
+ /* fill rx urb */
+ urb = usb->usb.rx_urb;
+ buf = usb->usb.rx_urb->transfer_buffer;
usb_fill_bulk_urb(urb, usb->usb.device, usb->usb.pipe.bulk.in,
buf, USB_CHR_RX_BUFSIZ,
baseband_usb_chr_rx_urb_comp,
@@ -653,12 +691,9 @@ static int baseband_usb_chr_rx_urb_submit(struct baseband_usb *usb)
/* submit rx urb */
usb->usb.rx_urb = urb;
- err = usb_submit_urb(urb, GFP_ATOMIC);
+ err = usb_submit_urb(urb, GFP_KERNEL);
if (err < 0) {
pr_err("usb_submit_urb() failed - err %d\n", err);
- usb->usb.rx_urb = (struct urb *) 0;
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
return err;
}
@@ -674,12 +709,22 @@ static void baseband_usb_chr_rx_urb_comp_work(struct work_struct *work)
pr_debug("baseband_usb_chr_rx_urb_comp_work { work %p\n", work);
+ if (usb_device_connection == false) {
+ /* device is closing or disconnect - nothing to read */
+ pr_info("%s: device is disconnected\n", __func__);
+ return;
+ }
/* put rx urb data in rx buffer */
if (urb->actual_length) {
pr_debug("baseband_usb_chr_rx_urb_comp_work - "
"urb->actual_length %d\n", urb->actual_length);
len = put_ipc_rx_buf(usb->ipc,
urb->transfer_buffer, urb->actual_length);
+ if (len == -ETIMEDOUT) {
+ /* device closed */
+ pr_info("%s: device closed\n", __func__);
+ return;
+ }
baseband_ipc_dump("baseband_usb_chr_rx_urb_comp_work"
" - rx buf ", 0,
urb->transfer_buffer, len > 16 ? 16 : len);
@@ -692,12 +737,6 @@ static void baseband_usb_chr_rx_urb_comp_work(struct work_struct *work)
atomic_add(len, &g_rx_count);
}
- /* free rx urb */
- kfree(urb->transfer_buffer);
- urb->transfer_buffer = (void *) 0;
- usb_free_urb(urb);
- usb->usb.rx_urb = (struct urb *) 0;
-
/* submit next rx urb */
baseband_usb_chr_rx_urb_submit(usb);
@@ -748,8 +787,6 @@ static void find_usb_pipe(struct baseband_usb *usb)
static int baseband_usb_driver_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- int err;
-
pr_debug("%s(%d) { intf %p id %p\n", __func__, __LINE__, intf, id);
pr_debug("intf->cur_altsetting->desc.bInterfaceNumber %02x\n",
@@ -775,38 +812,9 @@ static int baseband_usb_driver_probe(struct usb_interface *intf,
}
/* usb interface match */
- baseband_usb_chr->usb.device = interface_to_usbdev(intf);
- baseband_usb_chr->usb.interface = intf;
- find_usb_pipe(baseband_usb_chr);
- baseband_usb_chr->usb.rx_urb = (struct urb *) 0;
- baseband_usb_chr->usb.tx_urb = (struct urb *) 0;
- pr_debug("baseband_usb_chr->usb.driver->name %s\n",
- baseband_usb_chr->usb.driver->name);
- pr_debug("baseband_usb_chr->usb.device %p\n",
- baseband_usb_chr->usb.device);
- pr_debug("baseband_usb_chr->usb.interface %p\n",
- baseband_usb_chr->usb.interface);
- pr_debug("baseband_usb_chr->usb.pipe.isoch.in %x\n",
- baseband_usb_chr->usb.pipe.isoch.in);
- pr_debug("baseband_usb_chr->usb.pipe.isoch.out %x\n",
- baseband_usb_chr->usb.pipe.isoch.out);
- pr_debug("baseband_usb_chr->usb.pipe.bulk.in %x\n",
- baseband_usb_chr->usb.pipe.bulk.in);
- pr_debug("baseband_usb_chr->usb.pipe.bulk.out %x\n",
- baseband_usb_chr->usb.pipe.bulk.out);
- pr_debug("baseband_usb_chr->usb.pipe.interrupt.in %x\n",
- baseband_usb_chr->usb.pipe.interrupt.in);
- pr_debug("baseband_usb_chr->usb.pipe.interrupt.out %x\n",
- baseband_usb_chr->usb.pipe.interrupt.out);
+ probe_usb_intf = intf;
usb_device_connection = true;
- /* start usb rx */
- err = baseband_usb_chr_rx_urb_submit(baseband_usb_chr);
- if (err < 0) {
- pr_err("submit rx failed - err %d\n", err);
- return -ENODEV;
- }
-
pr_debug("%s(%d) }\n", __func__, __LINE__);
return 0;
}
@@ -815,17 +823,25 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
pr_debug("%s(%d) { intf %p\n", __func__, __LINE__, intf);
- pr_debug("%s(%d) }\n", __func__, __LINE__);
+
+ if (!baseband_usb_chr) {
+ pr_err("%s: no baseband_usb_chr\n", __func__);
+ return;
+ }
+
if (baseband_usb_chr->usb.interface != intf) {
pr_info("%s(%d) -ENODEV\n", __func__, __LINE__);
return;
}
if (baseband_usb_chr->usb.device == usb_dev) {
pr_info("%s: Matching usb device: Flush workqueue\n", __func__);
- flush_workqueue(baseband_usb_chr->ipc->workqueue);
+ /* flush queued ipc transaction work */
+ if (baseband_usb_chr && baseband_usb_chr->ipc
+ && baseband_usb_chr->ipc->workqueue)
+ flush_workqueue(baseband_usb_chr->ipc->workqueue);
usb_device_connection = false;
}
-
+ pr_debug("%s(%d) }\n", __func__, __LINE__);
}
static char baseband_usb_driver_name[32];
@@ -864,23 +880,15 @@ static void baseband_usb_chr_work(struct work_struct *work)
queue_work(usb->ipc->workqueue, &usb->ipc->work);
return;
}
-
- /* allocate buffers on first transaction (will be freed on close) */
if (!usb->ipc->ipc_rx) {
- usb->ipc->ipc_rx = kzalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
- if (!usb->ipc->ipc_rx) {
- pr_err("baseband_usb_chr_work - "
- "cannot allocate usb->ipc->ipc_rx\n");
- return;
- }
+ pr_err("baseband_usb_chr_work - "
+ "null usb->ipc->ipc_rx\n");
+ return;
}
if (!usb->ipc->ipc_tx) {
- usb->ipc->ipc_tx = kzalloc(USB_CHR_TX_BUFSIZ, GFP_KERNEL);
- if (!usb->ipc->ipc_tx) {
- pr_err("baseband_usb_chr_work - "
- "cannot allocate usb->ipc->ipc_tx\n");
- return;
- }
+ pr_err("baseband_usb_chr_work - "
+ "null usb->ipc->ipc_tx\n");
+ return;
}
/* usb transaction loop */
@@ -906,81 +914,6 @@ static void baseband_usb_chr_work(struct work_struct *work)
pr_debug("baseband_usb_chr_work }\n");
}
-/* usb character file operations */
-
-static int baseband_usb_chr_open(struct inode *inode, struct file *file)
-{
- pr_debug("baseband_usb_chr_open\n");
- return 0;
-}
-
-static int baseband_usb_chr_release(struct inode *inode, struct file *file)
-{
- pr_debug("baseband_usb_chr_release\n");
- return 0;
-}
-
-static ssize_t baseband_usb_chr_read(struct file *file, char *buf,
- size_t count, loff_t *pos)
-{
- ssize_t ret;
-
- pr_debug("baseband_usb_chr_read\n");
-
- ret = baseband_ipc_file_read(baseband_usb_chr->ipc,
- file, buf, count, pos);
- if (ret > 0) {
- /* decrement count of available rx bytes */
- int val = atomic_read(&g_rx_count);
- pr_debug("baseband_usb_chr_read - read %d unread %d\n",
- ret, val - ret);
- atomic_sub(ret, &g_rx_count);
- }
- return ret;
-}
-
-static ssize_t baseband_usb_chr_write(struct file *file, const char *buf,
- size_t count, loff_t *pos)
-{
- pr_debug("baseband_usb_chr_write\n");
- return baseband_ipc_file_write(baseband_usb_chr->ipc,
- file, buf, count, pos);
-}
-
-static long baseband_usb_chr_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- pr_debug("baseband_usb_chr_ioctl\n");
- switch (cmd) {
- case TCFLSH:
- pr_debug("TCFLSH\n");
- /* flush queued ipc transaction work */
- flush_workqueue(baseband_usb_chr->ipc->workqueue);
- return 0;
- case FIONREAD:
- pr_debug("FIONREAD\n");
- /* return count of available rx bytes */
- {
- int __user *p = (int __user *) arg;
- int val = atomic_read(&g_rx_count);
- if (put_user(val, p))
- break;
- }
- return 0;
- default:
- pr_err("unsupported ioctl cmd %x\n", cmd);
- }
- return -ENODEV;
-}
-
-static const struct file_operations baseband_usb_chr_fops = {
- .open = baseband_usb_chr_open,
- .release = baseband_usb_chr_release,
- .read = baseband_usb_chr_read,
- .write = baseband_usb_chr_write,
- .unlocked_ioctl = baseband_usb_chr_ioctl,
-};
-
/* usb device driver functions */
static void baseband_usb_close(struct baseband_usb *usb)
@@ -991,6 +924,23 @@ static void baseband_usb_close(struct baseband_usb *usb)
if (!usb)
return;
+ /* free re-usable rx urb + rx urb transfer buffer */
+ if (usb->usb.rx_urb) {
+ pr_debug("%s: free rx urb\n", __func__);
+ usb_kill_urb(usb->usb.rx_urb);
+ if (usb->usb.rx_urb->transfer_buffer) {
+ pr_debug("%s: free rx urb transfer buffer\n", __func__);
+ kfree(usb->usb.rx_urb->transfer_buffer);
+ usb->usb.rx_urb->transfer_buffer = (void *) 0;
+ }
+ }
+
+ if (usb->ipc) {
+ usb_device_connection = false;
+ flush_work_sync(&usb->ipc->work);
+ flush_work_sync(&usb->ipc->rx_work);
+ }
+
/* close usb driver */
if (usb->usb.driver) {
pr_debug("close usb driver {\n");
@@ -1002,11 +952,13 @@ static void baseband_usb_close(struct baseband_usb *usb)
/* close baseband ipc */
if (usb->ipc) {
baseband_ipc_close(usb->ipc);
- usb->ipc = (struct baseband_ipc *) 0;
+ usb_free_urb(usb->usb.rx_urb);
+ usb->usb.rx_urb = NULL;
+ usb->ipc = NULL;
}
/* free baseband usb structure */
- kfree(usb);
+ vfree(usb);
pr_debug("baseband_usb_close }\n");
}
@@ -1019,15 +971,17 @@ static struct baseband_usb *baseband_usb_open(unsigned int vid,
work_func_t tx_work_func)
{
struct baseband_usb *usb;
- int err;
+ int err, i;
+ struct urb *urb;
+ void *buf;
pr_debug("baseband_usb_open {\n");
/* allocate baseband usb structure */
- usb = kzalloc(sizeof(struct baseband_usb), GFP_KERNEL);
+ usb = vmalloc(sizeof(struct baseband_usb));
if (!usb)
return (struct baseband_usb *) 0;
- baseband_usb_chr = usb;
+ memset(usb, 0, sizeof(struct baseband_usb));
/* open baseband ipc */
usb->ipc = baseband_ipc_open(work_func,
@@ -1039,6 +993,7 @@ static struct baseband_usb *baseband_usb_open(unsigned int vid,
}
/* open usb driver */
+ probe_usb_intf = (struct usb_interface *) 0;
sprintf(baseband_usb_driver_name,
"baseband_usb_%x_%x_%x",
vid, pid, intf);
@@ -1053,6 +1008,65 @@ static struct baseband_usb *baseband_usb_open(unsigned int vid,
goto error_exit;
}
+ /* wait for probe */
+ pr_info("%s: waiting for usb probe...\n", __func__);
+ for (i = 0; i < 5 * 10; i++) {
+ if (probe_usb_intf && usb_device_connection)
+ break;
+ msleep(100);
+ }
+ if (!probe_usb_intf || !usb_device_connection) {
+ pr_info("%s: probe timed out!\n", __func__);
+ goto error_exit;
+ }
+
+ /* get probed usb device information */
+ usb->usb.device = interface_to_usbdev(probe_usb_intf);
+ usb->usb.interface = probe_usb_intf;
+ find_usb_pipe(usb);
+ usb->usb.rx_urb = (struct urb *) 0;
+ usb->usb.tx_urb = (struct urb *) 0;
+ pr_debug("usb->usb.driver->name %s\n",
+ usb->usb.driver->name);
+ pr_debug("usb->usb.device %p\n",
+ usb->usb.device);
+ pr_debug("usb->usb.interface %p\n",
+ usb->usb.interface);
+ pr_debug("usb->usb.pipe.isoch.in %x\n",
+ usb->usb.pipe.isoch.in);
+ pr_debug("usb->usb.pipe.isoch.out %x\n",
+ usb->usb.pipe.isoch.out);
+ pr_debug("usb->usb.pipe.bulk.in %x\n",
+ usb->usb.pipe.bulk.in);
+ pr_debug("usb->usb.pipe.bulk.out %x\n",
+ usb->usb.pipe.bulk.out);
+ pr_debug("usb->usb.pipe.interrupt.in %x\n",
+ usb->usb.pipe.interrupt.in);
+ pr_debug("usb->usb.pipe.interrupt.out %x\n",
+ usb->usb.pipe.interrupt.out);
+
+ /* allocate re-usable rx urb + rx urb transfer buffer */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ pr_err("usb_alloc_urb() failed\n");
+ goto error_exit;
+ }
+ buf = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+ if (!buf) {
+ pr_err("%s: usb buffer kmalloc() failed\n", __func__);
+ usb_free_urb(urb);
+ goto error_exit;
+ }
+ urb->transfer_buffer = buf;
+ usb->usb.rx_urb = urb;
+
+ /* start usb rx */
+ err = baseband_usb_chr_rx_urb_submit(usb);
+ if (err < 0) {
+ pr_err("submit rx failed - err %d\n", err);
+ goto error_exit;
+ }
+
pr_debug("baseband_usb_open }\n");
return usb;
@@ -1062,27 +1076,143 @@ error_exit:
return (struct baseband_usb *) 0;
}
-/* module init / exit functions */
-static int baseband_usb_chr_init(void)
+/* usb character file operations */
+
+static int baseband_usb_chr_open(struct inode *inode, struct file *file)
{
- int err;
+ pr_debug("baseband_usb_chr_open {\n");
- pr_debug("baseband_usb_chr_init {\n");
+ if (baseband_usb_chr) {
+ pr_err("%s: device is already open\n", __func__);
+ /* application uses two fd opens for download*/
+ baseband_usb_chr->ref++;
+ return 0;
+ }
/* open baseband usb */
- baseband_usb_chr = baseband_usb_open
- (baseband_usb_chr_vid,
- baseband_usb_chr_pid,
- baseband_usb_chr_intf,
- baseband_usb_chr_work,
- baseband_usb_chr_rx_urb_comp_work,
- (work_func_t) 0);
+ baseband_usb_chr = baseband_usb_open(baseband_usb_chr_vid,
+ baseband_usb_chr_pid,
+ baseband_usb_chr_intf,
+ baseband_usb_chr_work,
+ baseband_usb_chr_rx_urb_comp_work,
+ (work_func_t) 0);
if (!baseband_usb_chr) {
pr_err("cannot open baseband usb chr\n");
- err = -1;
- goto err1;
+ return -ENODEV;
+ }
+ baseband_usb_chr->ref++;
+
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
+ pr_debug("baseband_usb_chr_open }\n");
+ return 0;
+}
+
+static int baseband_usb_chr_release(struct inode *inode, struct file *file)
+{
+ pr_debug("baseband_usb_chr_release\n");
+ pr_info("baseband_usb_chr_release {\n");
+
+ if (baseband_usb_chr) {
+ baseband_usb_chr->ref--;
+ if (baseband_usb_chr->ref)
+ return 0;
+
+ /* close baseband usb */
+ baseband_usb_close(baseband_usb_chr);
+ baseband_usb_chr = (struct baseband_usb *) 0;
+ }
+
+ module_put(THIS_MODULE);
+ pr_info("baseband_usb_chr_release }\n");
+
+ return 0;
+}
+
+static ssize_t baseband_usb_chr_read(struct file *file, char *buf,
+ size_t count, loff_t *pos)
+{
+ ssize_t ret;
+
+ pr_debug("baseband_usb_chr_read\n");
+
+ if (!baseband_usb_chr || !baseband_usb_chr->ipc) {
+ pr_err("%s: -ENODEV\n", __func__);
+ return -ENODEV;
+ }
+ ret = baseband_ipc_file_read(baseband_usb_chr->ipc,
+ file, buf, count, pos);
+ if (ret > 0) {
+ /* decrement count of available rx bytes */
+ int val = atomic_read(&g_rx_count);
+ pr_debug("baseband_usb_chr_read - read %d unread %d\n",
+ ret, val - ret);
+ atomic_sub(ret, &g_rx_count);
+ }
+ return ret;
+}
+
+static ssize_t baseband_usb_chr_write(struct file *file, const char *buf,
+ size_t count, loff_t *pos)
+{
+ pr_debug("baseband_usb_chr_write\n");
+ if (!baseband_usb_chr || !baseband_usb_chr->ipc) {
+ pr_err("%s: -ENODEV\n", __func__);
+ return -ENODEV;
+ }
+ return baseband_ipc_file_write(baseband_usb_chr->ipc,
+ file, buf, count, pos);
+}
+
+static long baseband_usb_chr_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ pr_debug("baseband_usb_chr_ioctl\n");
+ switch (cmd) {
+ case TCFLSH:
+ pr_debug("TCFLSH\n");
+ /* flush queued ipc transaction work */
+ if (!baseband_usb_chr || !baseband_usb_chr->ipc
+ || !baseband_usb_chr->ipc->workqueue) {
+ pr_err("%s: no workqueue!\n", __func__);
+ return -ENODEV;
+ }
+ flush_workqueue(baseband_usb_chr->ipc->workqueue);
+ return 0;
+ case FIONREAD:
+ pr_debug("FIONREAD\n");
+ /* return count of available rx bytes */
+ {
+ int __user *p = (int __user *) arg;
+ int val = atomic_read(&g_rx_count);
+ if (put_user(val, p))
+ break;
+ }
+ return 0;
+ default:
+ pr_err("unsupported ioctl cmd %x\n", cmd);
+ return 0;
}
+ return -ENODEV;
+}
+
+static const struct file_operations baseband_usb_chr_fops = {
+ .open = baseband_usb_chr_open,
+ .release = baseband_usb_chr_release,
+ .read = baseband_usb_chr_read,
+ .write = baseband_usb_chr_write,
+ .unlocked_ioctl = baseband_usb_chr_ioctl,
+};
+
+/* module init / exit functions */
+
+static int baseband_usb_chr_init(void)
+{
+ int err;
+
+ pr_debug("baseband_usb_chr_init {\n");
/* register character device */
err = register_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
@@ -1090,16 +1220,22 @@ static int baseband_usb_chr_init(void)
&baseband_usb_chr_fops);
if (err < 0) {
pr_err("cannot register character device - %d\n", err);
- goto err2;
+ return err;
}
pr_debug("registered baseband usb character device - major %d\n",
BASEBAND_USB_CHR_DEV_MAJOR);
+ /* create workqueue thread */
+ chr_ipc_wq = create_singlethread_workqueue("baseband_chr_wq");
+ if (chr_ipc_wq == NULL) {
+ pr_err("cannot create workqueue\n");
+ unregister_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
+ BASEBAND_USB_CHR_DEV_NAME);
+ return -ENODEV;
+ }
+
pr_debug("baseband_usb_chr_init }\n");
return 0;
-err2: baseband_usb_close(baseband_usb_chr);
- baseband_usb_chr = (struct baseband_usb *) 0;
-err1: return err;
}
static void baseband_usb_chr_exit(void)
@@ -1110,12 +1246,10 @@ static void baseband_usb_chr_exit(void)
unregister_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
BASEBAND_USB_CHR_DEV_NAME);
- /* close baseband usb */
- if (baseband_usb_chr) {
- baseband_usb_close(baseband_usb_chr);
- baseband_usb_chr = (struct baseband_usb *) 0;
+ if (chr_ipc_wq) {
+ destroy_workqueue(chr_ipc_wq);
+ chr_ipc_wq = NULL;
}
-
pr_debug("baseband_usb_chr_exit }\n");
}
diff --git a/drivers/usb/serial/baseband_usb_chr.h b/drivers/usb/serial/baseband_usb_chr.h
index 7935e795a54d..e7553f76093e 100644
--- a/drivers/usb/serial/baseband_usb_chr.h
+++ b/drivers/usb/serial/baseband_usb_chr.h
@@ -27,11 +27,11 @@
#define BASEBAND_USB_CHR_DEV_MAJOR 66
#ifndef USB_CHR_RX_BUFSIZ
-#define USB_CHR_RX_BUFSIZ (128*1024)
+#define USB_CHR_RX_BUFSIZ (32*1024)
#endif /* USB_CHR_RX_BUFSIZ */
#ifndef USB_CHR_TX_BUFSIZ
-#define USB_CHR_TX_BUFSIZ (128*1024)
+#define USB_CHR_TX_BUFSIZ (32*1024)
#endif /* USB_CHR_TX_BUFSIZ */
#ifndef USB_CHR_TIMEOUT
@@ -39,11 +39,11 @@
#endif /* USB_CHR_TIMEOUT */
#ifndef BASEBAND_IPC_NUM_RX_BUF
-#define BASEBAND_IPC_NUM_RX_BUF 32
+#define BASEBAND_IPC_NUM_RX_BUF 1
#endif /* BASEBAND_IPC_NUM_RX_BUF */
#ifndef BASEBAND_IPC_NUM_TX_BUF
-#define BASEBAND_IPC_NUM_TX_BUF 16
+#define BASEBAND_IPC_NUM_TX_BUF 1
#endif /* BASEBAND_IPC_NUM_TX_BUF */
#ifndef BASEBAND_IPC_BUFSIZ
@@ -85,6 +85,7 @@ struct baseband_ipc_buf {
struct baseband_usb {
struct baseband_ipc *ipc;
+ unsigned int ref;
struct {
struct usb_driver *driver;
struct usb_device *device;
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 473875a3ae78..5e15a92609b0 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -1103,13 +1103,8 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
if (mx3_fbi->txd)
async_tx_ack(mx3_fbi->txd);
-<<<<<<< HEAD
- txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg +
- mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);
-=======
txd = dmaengine_prep_slave_sg(dma_chan, sg +
mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (!txd) {
dev_err(fbi->device,
"Error preparing a DMA transaction descriptor.\n");
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
index 7de26267155e..59e27788680d 100644
--- a/drivers/video/tegra/Kconfig
+++ b/drivers/video/tegra/Kconfig
@@ -53,7 +53,7 @@ config NVMAP_RECLAIM_UNPINNED_VM
config NVMAP_ALLOW_SYSMEM
bool "Allow physical system memory to be used by nvmap"
depends on TEGRA_NVMAP
- default y
+ default n
help
Say Y here to allow nvmap to use physical system memory (i.e.,
shared with the operating system but not translated through
@@ -85,6 +85,22 @@ config NVMAP_CARVEOUT_COMPACTOR
heap and retries the failed allocation.
Say Y here to let nvmap to keep carveout fragmentation under control.
+config NVMAP_PAGE_POOLS
+ bool "Use page pools to reduce allocation overhead"
+ depends on TEGRA_NVMAP
+ default y
+ help
+ say Y here to reduce the alloction overhead, which is significant
+ for uncached, writecombine and inner cacheable memories as it
+ involves changing page attributes during every allocation per page
+ and flushing cache. Alloc time is reduced by allcoating the pages
+ ahead and keeping them aside. The reserved pages would be released
+ when system is low on memory and acquired back during release of
+ memory.
+
+config NVMAP_PAGE_POOL_SIZE
+ hex
+ default 0x0
config NVMAP_VPR
bool "Enable VPR Heap."
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
index 01f13918ca63..ebe9e890fad6 100644
--- a/drivers/video/tegra/dc/Makefile
+++ b/drivers/video/tegra/dc/Makefile
@@ -7,4 +7,5 @@ obj-y += edid.o
obj-y += nvsd.o
obj-y += dsi.o
obj-y += dc_sysfs.o
+obj-y += dc_config.o
obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 5203fbba9efc..55d3fccf56b2 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -23,7 +23,6 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mutex.h>
@@ -34,6 +33,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/backlight.h>
+#include <linux/gpio.h>
#include <video/tegrafb.h>
#include <drm/drm_fixed.h>
#ifdef CONFIG_SWITCH
@@ -49,6 +49,7 @@
#include <mach/latency_allowance.h>
#include "dc_reg.h"
+#include "dc_config.h"
#include "dc_priv.h"
#include "nvsd.h"
@@ -64,9 +65,21 @@
#define ALL_UF_INT (0)
#endif
-static int calc_refresh(const struct tegra_dc_mode *m);
-
static int no_vsync;
+static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
+ .refresh = 60,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = KHZ2PICOS(25200),
+ .hsync_len = 96, /* h_sync_width */
+ .vsync_len = 2, /* v_sync_width */
+ .left_margin = 48, /* h_back_porch */
+ .upper_margin = 33, /* v_back_porch */
+ .right_margin = 16, /* h_front_porch */
+ .lower_margin = 10, /* v_front_porch */
+ .vmode = 0,
+ .sync = 0,
+};
static void _tegra_dc_controller_disable(struct tegra_dc *dc);
@@ -81,25 +94,14 @@ struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
DEFINE_MUTEX(shared_lock);
-static const struct {
- bool h;
- bool v;
-} can_filter[] = {
- /* Window A has no filtering */
- { false, false },
- /* Window B has both H and V filtering */
- { true, true },
- /* Window C has only H filtering */
- { false, true },
-};
-static inline bool win_use_v_filter(const struct tegra_dc_win *win)
+static inline bool win_use_v_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
{
- return can_filter[win->idx].v &&
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_V_FILTER) &&
win->h.full != dfixed_const(win->out_h);
}
-static inline bool win_use_h_filter(const struct tegra_dc_win *win)
+static inline bool win_use_h_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
{
- return can_filter[win->idx].h &&
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_H_FILTER) &&
win->w.full != dfixed_const(win->out_w);
}
@@ -141,14 +143,32 @@ static inline int tegra_dc_fmt_bpp(int fmt)
case TEGRA_WIN_FMT_YUV422RA:
return 8;
+ /* YUYV packed into 32-bits */
case TEGRA_WIN_FMT_YCbCr422:
case TEGRA_WIN_FMT_YUV422:
- /* FIXME: need to know the bpp of these formats */
- return 0;
+ return 16;
}
return 0;
}
+static inline bool tegra_dc_is_yuv(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return true;
+ }
+ return false;
+}
+
static inline bool tegra_dc_is_yuv_planar(int fmt)
{
switch (fmt) {
@@ -171,6 +191,34 @@ static inline bool tegra_dc_is_yuv_planar(int fmt)
print(data, buff); \
} while (0)
+#define print_mode_info(dc, mode) do { \
+ trace_printk("%s:Mode settings: " \
+ "ref_to_sync: H = %d V = %d, " \
+ "sync_width: H = %d V = %d, " \
+ "back_porch: H = %d V = %d, " \
+ "active: H = %d V = %d, " \
+ "front_porch: H = %d V = %d, " \
+ "pclk = %d, stereo mode = %d\n", \
+ dc->ndev->name, \
+ mode.h_ref_to_sync, mode.v_ref_to_sync, \
+ mode.h_sync_width, mode.v_sync_width, \
+ mode.h_back_porch, mode.v_back_porch, \
+ mode.h_active, mode.v_active, \
+ mode.h_front_porch, mode.v_front_porch, \
+ mode.pclk, mode.stereo_mode); \
+ } while (0)
+
+#define print_underflow_info(dc) do { \
+ trace_printk("%s:Underflow stats: underflows : %llu, " \
+ "undeflows_a : %llu, " \
+ "underflows_b : %llu, " \
+ "underflows_c : %llu\n", \
+ dc->ndev->name, \
+ dc->stats.underflows, \
+ dc->stats.underflows_a, dc->stats.underflows_b, \
+ dc->stats.underflows_c); \
+ } while (0)
+
static void _dump_regs(struct tegra_dc *dc, void *data,
void (* print)(void *data, const char *str))
{
@@ -571,6 +619,20 @@ bool tegra_dc_get_connected(struct tegra_dc *dc)
}
EXPORT_SYMBOL(tegra_dc_get_connected);
+bool tegra_dc_hpd(struct tegra_dc *dc)
+{
+ int sense;
+ int level;
+
+ level = gpio_get_value(dc->out->hotplug_gpio);
+
+ sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK;
+
+ return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) ||
+ (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level);
+}
+EXPORT_SYMBOL(tegra_dc_hpd);
+
static u32 blend_topwin(u32 flags)
{
if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
@@ -767,6 +829,8 @@ static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
mutex_unlock(&dc->lock);
+ tegra_dc_update_windows(&win, 1);
+
return 0;
}
@@ -828,7 +892,7 @@ static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
/* tegra_dc_get_bandwidth() treats V filter windows as double
* bandwidth, but LA has a seperate client for V filter */
- if (w->idx == 1 && win_use_v_filter(w))
+ if (w->idx == 1 && win_use_v_filter(dc, w))
bw /= 2;
/* our bandwidth is in kbytes/sec, but LA takes MBps.
@@ -946,14 +1010,9 @@ static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
* is of the luma plane's size only. */
bpp = tegra_dc_is_yuv_planar(w->fmt) ?
2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
- ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(w) ? 2 : 1)
+ ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(dc, w) ? 2 : 1)
* dfixed_trunc(w->w) / w->out_w *
(WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1);
- /*
- * Assuming ~35% efficiency: i.e. if we calculate we need 70MBps, we
- * will request 200MBps from EMC.
- */
- ret = ret * 29 / 10;
return ret;
}
@@ -981,6 +1040,8 @@ static unsigned long tegra_dc_get_bandwidth(
/* to save power, call when display memory clients would be idle */
static void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
{
+ trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
+ dc->emc_clk_rate);
if (tegra_is_clk_enabled(dc->emc_clk))
clk_disable(dc->emc_clk);
dc->emc_clk_rate = 0;
@@ -1007,6 +1068,8 @@ static void tegra_dc_program_bandwidth(struct tegra_dc *dc)
if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0)
tegra_dc_set_latency_allowance(dc, w);
+ trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
+ w->bandwidth);
}
}
@@ -1030,6 +1093,7 @@ static int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
if (tegra_dc_has_multiple_dc())
new_rate = ULONG_MAX;
+ trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
dc->new_emc_clk_rate = new_rate;
return 0;
@@ -1114,14 +1178,6 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
else
tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS);
- for (i = 0; i < DC_N_WINDOWS; i++) {
- tegra_dc_writel(dc, WINDOW_A_SELECT << i,
- DC_CMD_DISPLAY_WINDOW_HEADER);
- tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
- if (!no_vsync)
- update_mask |= WIN_A_ACT_REQ << i;
- }
-
for (i = 0; i < n; i++) {
struct tegra_dc_win *win = windows[i];
unsigned h_dda;
@@ -1129,12 +1185,13 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
fixed20_12 h_offset, v_offset;
bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
+ bool yuv = tegra_dc_is_yuv(win->fmt);
bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
/* Bytes per pixel of bandwidth, used for dda_inc calculation */
unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
- const bool filter_h = win_use_h_filter(win);
- const bool filter_v = win_use_v_filter(win);
+ const bool filter_h = win_use_h_filter(dc, win);
+ const bool filter_v = win_use_v_filter(dc, win);
if (win->z != dc->blend.z[win->idx]) {
dc->blend.z[win->idx] = win->z;
@@ -1158,8 +1215,8 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
continue;
}
- tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
- tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
+ tegra_dc_writel(dc, win->fmt & 0x1f, DC_WIN_COLOR_DEPTH);
+ tegra_dc_writel(dc, win->fmt >> 6, DC_WIN_BYTE_SWAP);
tegra_dc_writel(dc,
V_POSITION(win->out_y) | H_POSITION(win->out_x),
@@ -1167,19 +1224,22 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc,
V_SIZE(win->out_h) | H_SIZE(win->out_w),
DC_WIN_SIZE);
- tegra_dc_writel(dc,
- V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
- H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
- DC_WIN_PRESCALED_SIZE);
-
- h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
- v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
- tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
- DC_WIN_DDA_INCREMENT);
- h_dda = compute_initial_dda(win->x);
- v_dda = compute_initial_dda(win->y);
- tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
- tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+
+ if (tegra_dc_feature_has_scaling(dc, win->idx)) {
+ tegra_dc_writel(dc,
+ V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
+ H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
+ DC_WIN_PRESCALED_SIZE);
+
+ h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
+ v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
+ tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
+ DC_WIN_DDA_INCREMENT);
+ h_dda = compute_initial_dda(win->x);
+ v_dda = compute_initial_dda(win->y);
+ tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
+ tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+ }
tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
@@ -1217,19 +1277,21 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, dfixed_trunc(v_offset),
DC_WINBUF_ADDR_V_OFFSET);
- if (WIN_IS_TILED(win))
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_TILE |
- DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
- DC_WIN_BUFFER_ADDR_MODE);
- else
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_LINEAR |
- DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
- DC_WIN_BUFFER_ADDR_MODE);
+ if (tegra_dc_feature_has_tiling(dc, win->idx)) {
+ if (WIN_IS_TILED(win))
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_TILE |
+ DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ else
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR |
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ }
val = WIN_ENABLE;
- if (yuvp)
+ if (yuv)
val |= CSC_ENABLE;
else if (tegra_dc_fmt_bpp(win->fmt) < 24)
val |= COLOR_EXPAND;
@@ -1249,6 +1311,14 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ if (win->global_alpha == 255)
+ tegra_dc_writel(dc, 0, DC_WIN_GLOBAL_ALPHA);
+ else
+ tegra_dc_writel(dc, GLOBAL_ALPHA_ENABLE |
+ win->global_alpha, DC_WIN_GLOBAL_ALPHA);
+#endif
+
win->dirty = no_vsync ? 0 : 1;
dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d "
@@ -1259,6 +1329,9 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
dfixed_trunc(win->w), dfixed_trunc(win->h),
win->out_x, win->out_y, win->out_w, win->out_h,
win->fmt, yuvp, Bpp, filter_h, filter_v);
+ trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n",
+ dc->ndev->name, win->idx, dfixed_trunc(win->w),
+ dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt);
}
if (update_blend) {
@@ -1296,6 +1369,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
update_mask |= NC_HOST_TRIG;
tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+ trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
mutex_unlock(&dc->lock);
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
@@ -1353,6 +1427,7 @@ static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
/* does not support syncing windows on multiple dcs in one call */
int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
{
+ int ret;
if (n < 1 || n > DC_N_WINDOWS)
return -EINVAL;
@@ -1361,13 +1436,18 @@ int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
/* Don't want to timeout on simulator */
- return wait_event_interruptible(windows[0]->dc->wq,
+ ret = wait_event_interruptible(windows[0]->dc->wq,
tegra_dc_windows_are_clean(windows, n));
#else
- return wait_event_interruptible_timeout(windows[0]->dc->wq,
+ trace_printk("%s:Before wait_event_interruptible_timeout\n",
+ windows[0]->dc->ndev->name);
+ ret = wait_event_interruptible_timeout(windows[0]->dc->wq,
tegra_dc_windows_are_clean(windows, n),
HZ);
+ trace_printk("%s:After wait_event_interruptible_timeout\n",
+ windows[0]->dc->ndev->name);
#endif
+ return ret;
}
EXPORT_SYMBOL(tegra_dc_sync_windows);
@@ -1614,6 +1694,7 @@ static bool check_ref_to_sync(struct tegra_dc_mode *mode)
return true;
}
+#ifdef DEBUG
/* return in 1000ths of a Hertz */
static int calc_refresh(const struct tegra_dc_mode *m)
{
@@ -1628,7 +1709,6 @@ static int calc_refresh(const struct tegra_dc_mode *m)
return refresh;
}
-#ifdef DEBUG
static void print_mode(struct tegra_dc *dc,
const struct tegra_dc_mode *mode, const char *note)
{
@@ -1708,6 +1788,7 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
rate = tegra_dc_clk_get_rate(dc);
pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
+ trace_printk("%s:pclk=%ld\n", dc->ndev->name, pclk);
if (pclk < (mode->pclk / 100 * 99) ||
pclk > (mode->pclk / 100 * 109)) {
dev_err(&dc->ndev->dev,
@@ -1719,6 +1800,7 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
}
div = (rate * 2 / pclk) - 2;
+ trace_printk("%s:div=%ld\n", dc->ndev->name, div);
tegra_dc_writel(dc, 0x00010001,
DC_DISP_SHIFT_CLOCK_OPTIONS);
@@ -1733,18 +1815,14 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ print_mode_info(dc, dc->mode);
return 0;
}
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dc->mode_lock, flags);
memcpy(&dc->mode, mode, sizeof(dc->mode));
- dc->mode_dirty = true;
- spin_unlock_irqrestore(&dc->mode_lock, flags);
print_mode(dc, mode, __func__);
@@ -1752,46 +1830,6 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
}
EXPORT_SYMBOL(tegra_dc_set_mode);
-/* convert tegra_dc_mode to fb_videomode
- * return non-zero on error. */
-int tegra_dc_to_fb_videomode(struct fb_videomode *fbmode,
- const struct tegra_dc_mode *mode)
-{
- if (!fbmode || !mode || !mode->pclk)
- return -EINVAL;
-
- memset(fbmode, 0, sizeof(*fbmode));
-
- if (mode->rated_pclk >= 1000)
- fbmode->pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
- else if (mode->pclk >= 1000)
- fbmode->pixclock = KHZ2PICOS(mode->pclk / 1000);
- fbmode->hsync_len = mode->h_sync_width;
- fbmode->vsync_len = mode->v_sync_width;
- fbmode->left_margin = mode->h_back_porch;
- fbmode->upper_margin = mode->v_back_porch;
- fbmode->xres = mode->h_active;
- fbmode->yres = mode->v_active;
- fbmode->right_margin = mode->h_front_porch;
- fbmode->lower_margin = mode->v_front_porch;
- fbmode->vmode = FB_VMODE_NONINTERLACED;
- fbmode->vmode |= mode->stereo_mode ?
-#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- FB_VMODE_STEREO_FRAME_PACK
-#else
- FB_VMODE_STEREO_LEFT_RIGHT
-#endif
- : 0;
- fbmode->sync |= (mode->flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC) ?
- 0 : FB_SYNC_HOR_HIGH_ACT;
- fbmode->sync |= (mode->flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC) ?
- 0 : FB_SYNC_VERT_HIGH_ACT;
- fbmode->refresh = (calc_refresh(mode) + 500) / 1000;
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_to_fb_videomode);
-
int tegra_dc_set_fb_mode(struct tegra_dc *dc,
const struct fb_videomode *fbmode, bool stereo_mode)
{
@@ -2053,7 +2091,7 @@ u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
{
int crc = 0;
- if(!dc) {
+ if (!dc) {
dev_err(&dc->ndev->dev, "Failed to get dc.\n");
goto crc_error;
}
@@ -2133,15 +2171,21 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
int i;
dc->stats.underflows++;
- if (dc->underflow_mask & WIN_A_UF_INT)
+ if (dc->underflow_mask & WIN_A_UF_INT) {
dc->stats.underflows_a += tegra_dc_underflow_count(dc,
DC_WINBUF_AD_UFLOW_STATUS);
- if (dc->underflow_mask & WIN_B_UF_INT)
+ trace_printk("%s:Window A Underflow\n", dc->ndev->name);
+ }
+ if (dc->underflow_mask & WIN_B_UF_INT) {
dc->stats.underflows_b += tegra_dc_underflow_count(dc,
DC_WINBUF_BD_UFLOW_STATUS);
- if (dc->underflow_mask & WIN_C_UF_INT)
+ trace_printk("%s:Window B Underflow\n", dc->ndev->name);
+ }
+ if (dc->underflow_mask & WIN_C_UF_INT) {
dc->stats.underflows_c += tegra_dc_underflow_count(dc,
DC_WINBUF_CD_UFLOW_STATUS);
+ trace_printk("%s:Window C Underflow\n", dc->ndev->name);
+ }
/* Check for any underflow reset conditions */
for (i = 0; i < DC_N_WINDOWS; i++) {
@@ -2153,6 +2197,9 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
schedule_work(&dc->reset_work);
/* reset counter */
dc->windows[i].underflows = 0;
+ trace_printk("%s:Reset work scheduled for "
+ "window %c\n",
+ dc->ndev->name, (65 + i));
}
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -2185,6 +2232,7 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
dc->underflow_mask = 0;
val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
tegra_dc_writel(dc, val | ALL_UF_INT, DC_CMD_INT_MASK);
+ print_underflow_info(dc);
}
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
@@ -2200,18 +2248,6 @@ static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
return false;
}
-static void tegra_dc_update_mode(struct tegra_dc *dc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dc->mode_lock, flags);
- if (dc->mode_dirty) {
- tegra_dc_program_mode(dc, &dc->mode);
- dc->mode_dirty = false;
- }
- spin_unlock_irqrestore(&dc->mode_lock, flags);
-}
-
static void tegra_dc_trigger_windows(struct tegra_dc *dc)
{
u32 val, i;
@@ -2271,9 +2307,6 @@ static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
/* Mark the frame_end as complete. */
if (!completion_done(&dc->frame_end_complete))
complete(&dc->frame_end_complete);
-
- /* handle a mode change, if it was scheduled */
- tegra_dc_update_mode(dc);
}
}
@@ -2298,8 +2331,6 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
if (!completion_done(&dc->frame_end_complete))
complete(&dc->frame_end_complete);
- /* handle a mode change, if it was scheduled */
- tegra_dc_update_mode(dc);
tegra_dc_trigger_windows(dc);
}
}
@@ -2573,6 +2604,7 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
tegra_dc_ext_enable(dc->ext);
+ trace_printk("%s:enable\n", dc->ndev->name);
return true;
}
@@ -2634,14 +2666,40 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
_tegra_dc_controller_disable(dc);
}
+ trace_printk("%s:reset enable\n", dc->ndev->name);
return ret;
}
#endif
+static int _tegra_dc_set_default_videomode(struct tegra_dc *dc)
+{
+ return tegra_dc_set_fb_mode(dc, &tegra_dc_hdmi_fallback_mode, 0);
+}
+
static bool _tegra_dc_enable(struct tegra_dc *dc)
{
- if (dc->mode.pclk == 0)
- return false;
+ if (dc->mode.pclk == 0) {
+ switch (dc->out->type) {
+ case TEGRA_DC_OUT_HDMI:
+ /* DC enable called but no videomode is loaded.
+ Check if HDMI is connected, then set fallback mdoe */
+ if (tegra_dc_hpd(dc)) {
+ if (_tegra_dc_set_default_videomode(dc))
+ return false;
+ } else
+ return false;
+
+ break;
+
+ /* Do nothing for other outputs for now */
+ case TEGRA_DC_OUT_RGB:
+
+ case TEGRA_DC_OUT_DSI:
+
+ default:
+ return false;
+ }
+ }
if (!dc->out)
return false;
@@ -2659,6 +2717,7 @@ void tegra_dc_enable(struct tegra_dc *dc)
dc->enabled = _tegra_dc_enable(dc);
mutex_unlock(&dc->lock);
+ print_mode_info(dc, dc->mode);
}
static void _tegra_dc_controller_disable(struct tegra_dc *dc)
@@ -2691,12 +2750,15 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
/* flush any pending syncpt waits */
while (dc->syncpt[i].min < dc->syncpt[i].max) {
+ trace_printk("%s:syncpt flush id=%d\n", dc->ndev->name,
+ dc->syncpt[i].id);
dc->syncpt[i].min++;
nvhost_syncpt_cpu_incr(
&nvhost_get_host(dc->ndev)->syncpt,
dc->syncpt[i].id);
}
}
+ trace_printk("%s:disabled\n", dc->ndev->name);
}
void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable)
@@ -2781,6 +2843,7 @@ void tegra_dc_disable(struct tegra_dc *dc)
mutex_unlock(&dc->lock);
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
mutex_unlock(&dc->one_shot_lock);
+ print_mode_info(dc, dc->mode);
}
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -2834,6 +2897,7 @@ static void tegra_dc_reset_worker(struct work_struct *work)
unlock:
mutex_unlock(&dc->lock);
mutex_unlock(&shared_lock);
+ trace_printk("%s:reset complete\n", dc->ndev->name);
}
#endif
@@ -2862,7 +2926,8 @@ static ssize_t switch_modeset_print_mode(struct switch_dev *sdev, char *buf)
}
#endif
-static int tegra_dc_probe(struct nvhost_device *ndev)
+static int tegra_dc_probe(struct nvhost_device *ndev,
+ struct nvhost_device_id *id_table)
{
struct tegra_dc *dc;
struct clk *clk;
@@ -2949,12 +3014,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
*/
dc->emc_clk_rate = 0;
- if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
- dc->enabled = true;
-
mutex_init(&dc->lock);
mutex_init(&dc->one_shot_lock);
- spin_lock_init(&dc->mode_lock);
init_completion(&dc->frame_end_complete);
init_waitqueue_head(&dc->wq);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -2990,6 +3051,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
switch_dev_register(&dc->modeset_switch);
#endif
+ tegra_dc_feature_register(dc);
+
if (dc->pdata->default_out)
tegra_dc_set_out(dc, dc->pdata->default_out);
else
@@ -3004,22 +3067,19 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
dc->ext = NULL;
}
+ mutex_lock(&dc->lock);
+ if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
+ dc->enabled = _tegra_dc_enable(dc);
+ mutex_unlock(&dc->lock);
+
/* interrupt handler must be registered before tegra_fb_register() */
- if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED,
+ if (request_irq(irq, tegra_dc_irq, 0,
dev_name(&ndev->dev), dc)) {
dev_err(&ndev->dev, "request_irq %d failed\n", irq);
ret = -EBUSY;
goto err_put_emc_clk;
}
- /* hack to balance enable_irq calls in _tegra_dc_enable() */
- disable_dc_irq(dc->irq);
-
- mutex_lock(&dc->lock);
- if (dc->enabled)
- _tegra_dc_enable(dc);
- mutex_unlock(&dc->lock);
-
tegra_dc_create_debugfs(dc);
dev_info(&ndev->dev, "probed\n");
@@ -3041,22 +3101,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
dc->fb = NULL;
}
- if (dc->out && dc->out->n_modes) {
- struct fb_monspecs specs;
- int i;
-
- memset(&specs, 0, sizeof(specs));
- specs.max_x = dc->mode.h_active * 1000;
- specs.max_y = dc->mode.v_active * 1000;
- specs.modedb_len = dc->out->n_modes;
- specs.modedb = kzalloc(specs.modedb_len *
- sizeof(struct fb_videomode), GFP_KERNEL);
- for (i = 0; i < dc->out->n_modes; i++)
- tegra_dc_to_fb_videomode(&specs.modedb[i],
- &dc->out->modes[i]);
- tegra_fb_update_monspecs(dc->fb, &specs, NULL);
- }
-
if (dc->out && dc->out->hotplug_init)
dc->out->hotplug_init();
@@ -3127,6 +3171,7 @@ static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state)
{
struct tegra_dc *dc = nvhost_get_drvdata(ndev);
+ trace_printk("%s:suspend\n", dc->ndev->name);
dev_info(&ndev->dev, "suspend\n");
tegra_dc_ext_disable(dc->ext);
@@ -3160,6 +3205,7 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
{
struct tegra_dc *dc = nvhost_get_drvdata(ndev);
+ trace_printk("%s:resume\n", dc->ndev->name);
dev_info(&ndev->dev, "resume\n");
mutex_lock(&dc->lock);
diff --git a/drivers/video/tegra/dc/dc_config.c b/drivers/video/tegra/dc/dc_config.c
new file mode 100644
index 000000000000..a40712f5dca1
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.c
@@ -0,0 +1,246 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "dc_config.h"
+
+static struct tegra_dc_feature_entry t20_feature_entries_a[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t20_feature_entries_b[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t20_feature_table_a = {
+ ARRAY_SIZE(t20_feature_entries_a), t20_feature_entries_a,
+};
+
+struct tegra_dc_feature t20_feature_table_b = {
+ ARRAY_SIZE(t20_feature_entries_b), t20_feature_entries_b,
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_a[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_b[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t30_feature_table_a = {
+ ARRAY_SIZE(t30_feature_entries_a), t30_feature_entries_a,
+};
+
+struct tegra_dc_feature t30_feature_table_b = {
+ ARRAY_SIZE(t30_feature_entries_b), t30_feature_entries_b,
+};
+
+int tegra_dc_get_feature(struct tegra_dc_feature *feature, int win_idx,
+ enum tegra_dc_feature_option option)
+{
+ int i;
+ struct tegra_dc_feature_entry *entry;
+
+ if (!feature)
+ return -EINVAL;
+
+ for (i = 0; i < feature->num_entries; i++) {
+ entry = &feature->entries[i];
+ if (entry->window_index == win_idx && entry->option == option)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation)
+{
+ int idx;
+ struct tegra_dc_feature_entry *entry;
+ enum tegra_dc_feature_option option;
+ struct tegra_dc_feature *feature = dc->feature;
+
+ switch (operation) {
+ case GET_WIN_FORMATS:
+ option = TEGRA_DC_FEATURE_FORMATS;
+ break;
+ case GET_WIN_SIZE:
+ option = TEGRA_DC_FEATURE_MAXIMUM_SIZE;
+ break;
+ case HAS_SCALE:
+ option = TEGRA_DC_FEATURE_MAXIMUM_SCALE;
+ break;
+ case HAS_TILED:
+ option = TEGRA_DC_FEATURE_LAYOUT_TYPE;
+ break;
+ case HAS_V_FILTER:
+ option = TEGRA_DC_FEATURE_FILTER_TYPE;
+ break;
+ case HAS_H_FILTER:
+ option = TEGRA_DC_FEATURE_FILTER_TYPE;
+ break;
+ case HAS_GEN2_BLEND:
+ option = TEGRA_DC_FEATURE_BLEND_TYPE;
+ break;
+ default:
+ return NULL;
+ }
+
+ idx = tegra_dc_get_feature(feature, win_idx, option);
+ if (IS_ERR_VALUE(idx))
+ return NULL;
+ entry = &feature->entries[idx];
+
+ return entry->arg;
+}
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx)
+{
+ int i;
+ long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_SCALE);
+
+ for (i = 0; i < ENTRY_SIZE; i++)
+ if (addr[i] != 1)
+ return 1;
+ return 0;
+}
+
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx)
+{
+ long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_TILED);
+
+ return addr[TILED_LAYOUT];
+}
+
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation)
+{
+ long *addr = tegra_dc_parse_feature(dc, win_idx, operation);
+
+ if (operation == HAS_V_FILTER)
+ return addr[V_FILTER];
+ else
+ return addr[H_FILTER];
+}
+
+void tegra_dc_feature_register(struct tegra_dc *dc)
+{
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ if (!dc->ndev->id)
+ dc->feature = &t20_feature_table_a;
+ else
+ dc->feature = &t20_feature_table_b;
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ if (!dc->ndev->id)
+ dc->feature = &t30_feature_table_a;
+ else
+ dc->feature = &t30_feature_table_b;
+#endif
+}
diff --git a/drivers/video/tegra/dc/dc_config.h b/drivers/video/tegra/dc/dc_config.h
new file mode 100644
index 000000000000..f513cd06dc45
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.h
@@ -0,0 +1,148 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+#define __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+
+#include <linux/errno.h>
+#include <mach/dc.h>
+
+#include "dc_priv.h"
+
+#define ENTRY_SIZE 4 /* Size of feature entry args */
+
+/* Define the supported formats. TEGRA_WIN_FMT_WIN_x macros are defined
+ * based on T20/T30 formats. */
+#define TEGRA_WIN_FMT_BASE_CNT (TEGRA_WIN_FMT_YUV422RA + 1)
+#define TEGRA_WIN_FMT_BASE ((1 << TEGRA_WIN_FMT_P8) | \
+ (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+ (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+ (1 << TEGRA_WIN_FMT_B5G6R5) | \
+ (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+ (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+ (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422) | \
+ (1 << TEGRA_WIN_FMT_YUV422) | \
+ (1 << TEGRA_WIN_FMT_YCbCr420P) | \
+ (1 << TEGRA_WIN_FMT_YUV420P) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422P) | \
+ (1 << TEGRA_WIN_FMT_YUV422P) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422R) | \
+ (1 << TEGRA_WIN_FMT_YUV422R))
+
+#define TEGRA_WIN_FMT_WIN_A ((1 << TEGRA_WIN_FMT_P1) | \
+ (1 << TEGRA_WIN_FMT_P2) | \
+ (1 << TEGRA_WIN_FMT_P4) | \
+ (1 << TEGRA_WIN_FMT_P8) | \
+ (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+ (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+ (1 << TEGRA_WIN_FMT_B5G6R5) | \
+ (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+ (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+ (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8))
+
+#define TEGRA_WIN_FMT_WIN_B (TEGRA_WIN_FMT_BASE | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+ (1 << TEGRA_WIN_FMT_YUV422RA))
+
+#define TEGRA_WIN_FMT_WIN_C (TEGRA_WIN_FMT_BASE | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+ (1 << TEGRA_WIN_FMT_YUV422RA))
+
+/* preferred formats do not include 32-bpp formats */
+#define TEGRA_WIN_PREF_FMT_WIN_B (TEGRA_WIN_FMT_WIN_B & \
+ ~(1 << TEGRA_WIN_FMT_B8G8R8A8) & \
+ ~(1 << TEGRA_WIN_FMT_R8G8B8A8))
+
+
+
+/* For each entry, we define the offset to read specific feature. Define the
+ * offset for TEGRA_DC_FEATURE_MAXIMUM_SCALE */
+#define H_SCALE_UP 0
+#define V_SCALE_UP 1
+#define H_FILTER_DOWN 2
+#define V_FILTER_DOWN 3
+
+/* Define the offset for TEGRA_DC_FEATURE_MAXIMUM_SIZE */
+#define MAX_WIDTH 0
+#define MIN_WIDTH 1
+#define MAX_HEIGHT 2
+#define MIN_HEIGHT 3
+#define CHECK_SIZE(val, min, max) ( \
+ ((val) < (min) || (val) > (max)) ? -EINVAL : 0)
+
+/* Define the offset for TEGRA_DC_FEATURE_FILTER_TYPE */
+#define V_FILTER 0
+#define H_FILTER 1
+
+/* Define the offset for TEGRA_DC_FEATURE_INVERT_TYPE */
+#define H_INVERT 0
+#define V_INVERT 1
+#define SCAN_COLUMN 2
+
+/* Define the offset for TEGRA_DC_FEATURE_LAYOUT_TYPE. */
+#define PITCHED_LAYOUT 0
+#define TILED_LAYOUT 1
+
+/* Available operations on feature table. */
+enum {
+ HAS_SCALE,
+ HAS_TILED,
+ HAS_V_FILTER,
+ HAS_H_FILTER,
+ HAS_GEN2_BLEND,
+ GET_WIN_FORMATS,
+ GET_WIN_SIZE,
+};
+
+enum tegra_dc_feature_option {
+ TEGRA_DC_FEATURE_FORMATS,
+ TEGRA_DC_FEATURE_BLEND_TYPE,
+ TEGRA_DC_FEATURE_MAXIMUM_SIZE,
+ TEGRA_DC_FEATURE_MAXIMUM_SCALE,
+ TEGRA_DC_FEATURE_FILTER_TYPE,
+ TEGRA_DC_FEATURE_LAYOUT_TYPE,
+ TEGRA_DC_FEATURE_INVERT_TYPE,
+ TEGRA_DC_FEATURE_PREFERRED_FORMATS,
+};
+
+struct tegra_dc_feature_entry {
+ int window_index;
+ enum tegra_dc_feature_option option;
+ long arg[ENTRY_SIZE];
+};
+
+struct tegra_dc_feature {
+ unsigned num_entries;
+ struct tegra_dc_feature_entry *entries;
+};
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation);
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation);
+void tegra_dc_feature_register(struct tegra_dc *dc);
+#endif
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 5cba88f9e806..ce7ac3c7b0d0 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -4,8 +4,6 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
- *
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
@@ -23,12 +21,14 @@
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/wait.h>
+#include <linux/fb.h>
#include <linux/completion.h>
#include <linux/switch.h>
#include <mach/dc.h>
#include "../host/dev.h"
+#include "../host/nvhost_acm.h"
#include "../host/host1x/host1x_syncpt.h"
#include <mach/tegra_dc_ext.h>
@@ -65,11 +65,13 @@ struct tegra_dc_out_ops {
void (*enable)(struct tegra_dc *dc);
/* disable output. dc clocks are on at this point */
void (*disable)(struct tegra_dc *dc);
-
/* suspend output. dc clocks are on at this point */
void (*suspend)(struct tegra_dc *dc);
/* resume output. dc clocks are on at this point */
void (*resume)(struct tegra_dc *dc);
+ /* mode filter. to provide a list of supported modes*/
+ bool (*mode_filter)(const struct tegra_dc *dc,
+ struct fb_videomode *mode);
};
struct tegra_dc {
@@ -95,8 +97,6 @@ struct tegra_dc {
void *out_data;
struct tegra_dc_mode mode;
- bool mode_dirty;
- spinlock_t mode_lock;
struct tegra_dc_win windows[DC_N_WINDOWS];
struct tegra_dc_blend blend;
@@ -137,6 +137,8 @@ struct tegra_dc {
struct tegra_dc_ext *ext;
+ struct tegra_dc_feature *feature;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugdir;
#endif
@@ -159,14 +161,19 @@ static inline void tegra_dc_io_end(struct tegra_dc *dc)
static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
unsigned long reg)
{
+ unsigned long ret;
+
BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
- return readl(dc->base + reg * 4);
+ ret = readl(dc->base + reg * 4);
+ trace_printk("readl %p=%#08lx\n", dc->base + reg * 4, ret);
+ return ret;
}
static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val,
unsigned long reg)
{
BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
+ trace_printk("writel %p=%#08lx\n", dc->base + reg * 4, val);
writel(val, dc->base + reg * 4);
}
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index 2b8f8becb15b..ded64de2decc 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -460,6 +460,12 @@
#define DC_WIN_HP_FETCH_CONTROL 0x714
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+#define DC_WIN_GLOBAL_ALPHA 0x715
+#define GLOBAL_ALPHA_ENABLE 0x10000
+#endif
+
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_START_ADDR_NS 0x801
#define DC_WINBUF_START_ADDR_U 0x802
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index c33d6e0a58b3..69cc60f70f1c 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -24,6 +24,8 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <mach/clk.h>
#include <mach/dc.h>
@@ -107,6 +109,7 @@ struct tegra_dc_dsi_data {
struct clk *dc_clk;
struct clk *dsi_clk;
+ struct clk *dsi_fixed_clk;
bool clk_ref;
struct mutex lock;
@@ -287,18 +290,128 @@ const u32 init_reg[] = {
inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
{
+ unsigned long ret;
+
BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
- return readl(dsi->base + reg * 4);
+ ret = readl(dsi->base + reg * 4);
+ trace_printk("readl %p=%#08lx\n", dsi->base + reg * 4, ret);
+ return ret;
}
EXPORT_SYMBOL(tegra_dsi_readl);
inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi, u32 val, u32 reg)
{
BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
+ trace_printk("writel %p=%#08x\n", dsi->base + reg * 4, val);
writel(val, dsi->base + reg * 4);
}
EXPORT_SYMBOL(tegra_dsi_writel);
+#ifdef CONFIG_DEBUG_FS
+static int dbg_dsi_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc_dsi_data *dsi = s->private;
+
+#define DUMP_REG(a) do { \
+ seq_printf(s, "%-32s\t%03x\t%08lx\n", \
+ #a, a, tegra_dsi_readl(dsi, a)); \
+ } while (0)
+
+ tegra_dc_io_start(dsi->dc);
+ clk_enable(dsi->dsi_clk);
+
+ DUMP_REG(DSI_INCR_SYNCPT_CNTRL);
+ DUMP_REG(DSI_INCR_SYNCPT_ERROR);
+ DUMP_REG(DSI_CTXSW);
+ DUMP_REG(DSI_POWER_CONTROL);
+ DUMP_REG(DSI_INT_ENABLE);
+ DUMP_REG(DSI_CONTROL);
+ DUMP_REG(DSI_SOL_DELAY);
+ DUMP_REG(DSI_MAX_THRESHOLD);
+ DUMP_REG(DSI_TRIGGER);
+ DUMP_REG(DSI_TX_CRC);
+ DUMP_REG(DSI_STATUS);
+ DUMP_REG(DSI_INIT_SEQ_CONTROL);
+ DUMP_REG(DSI_INIT_SEQ_DATA_0);
+ DUMP_REG(DSI_INIT_SEQ_DATA_1);
+ DUMP_REG(DSI_INIT_SEQ_DATA_2);
+ DUMP_REG(DSI_INIT_SEQ_DATA_3);
+ DUMP_REG(DSI_INIT_SEQ_DATA_4);
+ DUMP_REG(DSI_INIT_SEQ_DATA_5);
+ DUMP_REG(DSI_INIT_SEQ_DATA_6);
+ DUMP_REG(DSI_INIT_SEQ_DATA_7);
+ DUMP_REG(DSI_PKT_SEQ_0_LO);
+ DUMP_REG(DSI_PKT_SEQ_0_HI);
+ DUMP_REG(DSI_PKT_SEQ_1_LO);
+ DUMP_REG(DSI_PKT_SEQ_1_HI);
+ DUMP_REG(DSI_PKT_SEQ_2_LO);
+ DUMP_REG(DSI_PKT_SEQ_2_HI);
+ DUMP_REG(DSI_PKT_SEQ_3_LO);
+ DUMP_REG(DSI_PKT_SEQ_3_HI);
+ DUMP_REG(DSI_PKT_SEQ_4_LO);
+ DUMP_REG(DSI_PKT_SEQ_4_HI);
+ DUMP_REG(DSI_PKT_SEQ_5_LO);
+ DUMP_REG(DSI_PKT_SEQ_5_HI);
+ DUMP_REG(DSI_DCS_CMDS);
+ DUMP_REG(DSI_PKT_LEN_0_1);
+ DUMP_REG(DSI_PKT_LEN_2_3);
+ DUMP_REG(DSI_PKT_LEN_4_5);
+ DUMP_REG(DSI_PKT_LEN_6_7);
+ DUMP_REG(DSI_PHY_TIMING_0);
+ DUMP_REG(DSI_PHY_TIMING_1);
+ DUMP_REG(DSI_PHY_TIMING_2);
+ DUMP_REG(DSI_BTA_TIMING);
+ DUMP_REG(DSI_TIMEOUT_0);
+ DUMP_REG(DSI_TIMEOUT_1);
+ DUMP_REG(DSI_TO_TALLY);
+ DUMP_REG(DSI_PAD_CONTROL);
+ DUMP_REG(DSI_PAD_CONTROL_CD);
+ DUMP_REG(DSI_PAD_CD_STATUS);
+ DUMP_REG(DSI_VID_MODE_CONTROL);
+#undef DUMP_REG
+
+ clk_disable(dsi->dsi_clk);
+ tegra_dc_io_end(dsi->dc);
+
+ return 0;
+}
+
+static int dbg_dsi_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_dsi_show, inode->i_private);
+}
+
+static const struct file_operations dbg_fops = {
+ .open = dbg_dsi_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *dsidir;
+
+static void tegra_dc_dsi_debug_create(struct tegra_dc_dsi_data *dsi)
+{
+ struct dentry *retval;
+
+ dsidir = debugfs_create_dir("tegra_dsi", NULL);
+ if (!dsidir)
+ return;
+ retval = debugfs_create_file("regs", S_IRUGO, dsidir, dsi,
+ &dbg_fops);
+ if (!retval)
+ goto free_out;
+ return;
+free_out:
+ debugfs_remove_recursive(dsidir);
+ dsidir = NULL;
+ return;
+}
+#else
+static inline void tegra_dc_dsi_debug_create(struct tegra_dc_dsi_data *dsi)
+{ }
+#endif
+
static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi)
{
u32 val;
@@ -1341,6 +1454,7 @@ static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc,
if (!dsi->clk_ref) {
dsi->clk_ref = true;
clk_enable(dsi->dsi_clk);
+ clk_enable(dsi->dsi_fixed_clk);
tegra_periph_reset_deassert(dsi->dsi_clk);
}
dsi->current_dsi_clk_khz = clk_get_rate(dsi->dsi_clk) / 1000;
@@ -1817,6 +1931,10 @@ static struct dsi_status *tegra_dsi_prepare_host_transmission(
if (tegra_dsi_host_busy(dsi)) {
tegra_dsi_soft_reset(dsi);
+
+ /* WAR to stop host write in middle */
+ tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_TRIGGER);
+
if (tegra_dsi_host_busy(dsi)) {
err = -EBUSY;
dev_err(&dc->ndev->dev, "DSI host busy\n");
@@ -2584,6 +2702,7 @@ static void _tegra_dc_dsi_init(struct tegra_dc *dc)
{
struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+ tegra_dc_dsi_debug_create(dsi);
tegra_dsi_init_sw(dc, dsi);
/* TODO: Configure the CSI pad configuration */
}
@@ -2748,6 +2867,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
void __iomem *base;
struct clk *dc_clk = NULL;
struct clk *dsi_clk = NULL;
+ struct clk *dsi_fixed_clk = NULL;
struct tegra_dsi_out *dsi_pdata;
int err;
@@ -2790,8 +2910,9 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
dsi_clk = clk_get(&dc->ndev->dev, "dsib");
else
dsi_clk = clk_get(&dc->ndev->dev, "dsia");
+ dsi_fixed_clk = clk_get(&dc->ndev->dev, "dsi-fixed");
- if (IS_ERR_OR_NULL(dsi_clk)) {
+ if (IS_ERR_OR_NULL(dsi_clk) || IS_ERR_OR_NULL(dsi_fixed_clk)) {
dev_err(&dc->ndev->dev, "dsi: can't get clock\n");
err = -EBUSY;
goto err_release_regs;
@@ -2811,6 +2932,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
dsi->base_res = base_res;
dsi->dc_clk = dc_clk;
dsi->dsi_clk = dsi_clk;
+ dsi->dsi_fixed_clk = dsi_fixed_clk;
err = tegra_dc_dsi_cp_info(dsi, dsi_pdata);
if (err < 0)
@@ -2824,6 +2946,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
err_dsi_data:
err_clk_put:
clk_put(dsi_clk);
+ clk_put(dsi_fixed_clk);
err_release_regs:
release_resource(base_res);
err_free_dsi:
@@ -2937,6 +3060,7 @@ static int tegra_dsi_deep_sleep(struct tegra_dc *dc,
/* Disable dsi source clock */
clk_disable(dsi->dsi_clk);
+ clk_disable(dsi->dsi_fixed_clk);
dsi->clk_ref = false;
dsi->enabled = false;
diff --git a/drivers/video/tegra/dc/ext/Makefile b/drivers/video/tegra/dc/ext/Makefile
index 19860ab5db11..343217ccc4a8 100644
--- a/drivers/video/tegra/dc/ext/Makefile
+++ b/drivers/video/tegra/dc/ext/Makefile
@@ -1,3 +1,4 @@
+GCOV_PROFILE := y
obj-y += dev.o
obj-y += util.o
obj-y += cursor.o
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 04553e778390..c349a4720d2e 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -27,11 +27,12 @@
#include <video/tegra_dc_ext.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/tegra_dc_ext.h>
/* XXX ew */
#include "../dc_priv.h"
+#include "../dc_config.h"
/* XXX ew 2 */
#include "../../host/dev.h"
/* XXX ew 3 */
@@ -172,10 +173,39 @@ void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
}
}
+int tegra_dc_ext_check_windowattr(struct tegra_dc_ext *ext,
+ struct tegra_dc_win *win)
+{
+ long *addr;
+ struct tegra_dc *dc = ext->dc;
+
+ /* Check the window format */
+ addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_FORMATS);
+ if (!test_bit(win->fmt, addr)) {
+ dev_err(&dc->ndev->dev, "Color format of window %d is"
+ " invalid.\n", win->idx);
+ goto fail;
+ }
+
+ /* Check window size */
+ addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_SIZE);
+ if (CHECK_SIZE(win->out_w, addr[MIN_WIDTH], addr[MAX_WIDTH]) ||
+ CHECK_SIZE(win->out_h, addr[MIN_HEIGHT], addr[MAX_HEIGHT])) {
+ dev_err(&dc->ndev->dev, "Size of window %d is"
+ " invalid.\n", win->idx);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
struct tegra_dc_win *win,
const struct tegra_dc_ext_flip_win *flip_win)
{
+ int err = 0;
struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
if (flip_win->handle[TEGRA_DC_Y] == NULL) {
@@ -195,6 +225,10 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
win->flags |= TEGRA_WIN_FLAG_INVERT_H;
if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_V)
win->flags |= TEGRA_WIN_FLAG_INVERT_V;
+ if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA)
+ win->global_alpha = flip_win->attr.global_alpha;
+ else
+ win->global_alpha = 255;
win->fmt = flip_win->attr.pixformat;
win->x.full = flip_win->attr.x;
win->y.full = flip_win->attr.y;
@@ -223,6 +257,11 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
win->stride = flip_win->attr.stride;
win->stride_uv = flip_win->attr.stride_uv;
+ err = tegra_dc_ext_check_windowattr(ext, win);
+ if (err < 0)
+ dev_err(&ext->dc->ndev->dev,
+ "Window atrributes are invalid.\n");
+
if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
nvhost_syncpt_wait_timeout(
&nvhost_get_host(ext->dc->ndev)->syncpt,
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index 95a637d5a52a..2a0c5497b7cb 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -25,7 +25,7 @@
#include <linux/poll.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <video/tegra_dc_ext.h>
diff --git a/drivers/video/tegra/dc/ext/util.c b/drivers/video/tegra/dc/ext/util.c
index 747085579f15..cede642372f3 100644
--- a/drivers/video/tegra/dc/ext/util.c
+++ b/drivers/video/tegra/dc/ext/util.c
@@ -20,7 +20,7 @@
#include <linux/types.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
/* ugh */
#include "../../nvmap/nvmap.h"
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 2e1df8d82641..59b9afcec0e4 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -67,6 +67,28 @@
#define HDMI_ELD_PRODUCT_CODE_INDEX 18
#define HDMI_ELD_MONITOR_NAME_INDEX 20
+/* These two values need to be cross checked in case of
+ addition/removal from tegra_dc_hdmi_aspect_ratios[] */
+#define TEGRA_DC_HDMI_MIN_ASPECT_RATIO_PERCENT 80
+#define TEGRA_DC_HDMI_MAX_ASPECT_RATIO_PERCENT 320
+
+/* Percentage equivalent of standard aspect ratios
+ accurate upto two decimal digits */
+static int tegra_dc_hdmi_aspect_ratios[] = {
+ /* 3:2 */ 150,
+ /* 4:3 */ 133,
+ /* 4:5 */ 80,
+ /* 5:4 */ 125,
+ /* 9:5 */ 180,
+ /* 16:5 */ 320,
+ /* 16:9 */ 178,
+ /* 16:10 */ 160,
+ /* 19:10 */ 190,
+ /* 25:16 */ 156,
+ /* 64:35 */ 183,
+ /* 72:35 */ 206
+};
+
struct tegra_dc_hdmi_data {
struct tegra_dc *dc;
struct tegra_edid *edid;
@@ -94,6 +116,7 @@ struct tegra_dc_hdmi_data {
bool clk_enabled;
unsigned audio_freq;
unsigned audio_source;
+ bool audio_inject_null;
bool dvi;
};
@@ -947,12 +970,16 @@ static const struct tegra_hdmi_audio_config
unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
unsigned long reg)
{
- return readl(hdmi->base + reg * 4);
+ unsigned long ret;
+ ret = readl(hdmi->base + reg * 4);
+ trace_printk("readl %p=%#08lx\n", hdmi->base + reg * 4, ret);
+ return ret;
}
void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
unsigned long val, unsigned long reg)
{
+ trace_printk("writel %p=%#08lx\n", hdmi->base + reg * 4, val);
writel(val, hdmi->base + reg * 4);
}
@@ -1240,62 +1267,84 @@ static bool tegra_dc_reload_mode(struct fb_videomode *mode)
return false;
}
+static bool tegra_dc_hdmi_valid_asp_ratio(const struct tegra_dc *dc,
+ struct fb_videomode *mode)
+{
+ int count = 0;
+ int m_aspratio = 0;
+ int s_aspratio = 0;
+
+ /* To check the aspect upto two decimal digits, calculate in % */
+ m_aspratio = (mode->xres*100 / mode->yres);
+
+ if ((m_aspratio < TEGRA_DC_HDMI_MIN_ASPECT_RATIO_PERCENT) ||
+ (m_aspratio > TEGRA_DC_HDMI_MAX_ASPECT_RATIO_PERCENT))
+ return false;
+
+ /* Check from the table of supported aspect ratios, allow
+ difference of 1% for second decimal digit calibration */
+ for (count = 0; count < ARRAY_SIZE(tegra_dc_hdmi_aspect_ratios);
+ count++) {
+ s_aspratio = tegra_dc_hdmi_aspect_ratios[count];
+ if ((m_aspratio == s_aspratio) ||
+ (abs(m_aspratio - s_aspratio) == 1))
+ return true;
+ }
+
+ return false;
+}
+
static bool tegra_dc_hdmi_mode_filter(const struct tegra_dc *dc,
struct fb_videomode *mode)
{
- int i;
- int clock_per_frame;
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ return false;
+ /* Ignore modes with a 0 pixel clock */
if (!mode->pixclock)
return false;
#ifdef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- if (PICOS2KHZ(mode->pixclock) > 74250)
- return false;
+ if (PICOS2KHZ(mode->pixclock) > 74250)
+ return false;
#endif
- for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_modes); i++) {
- const struct fb_videomode *supported_mode
- = &tegra_dc_hdmi_supported_modes[i];
- if (tegra_dc_hdmi_mode_equal(supported_mode, mode) &&
- tegra_dc_hdmi_valid_pixclock(dc, supported_mode)) {
- if (mode->lower_margin == 1) {
- /* This might be the case for HDMI<->DVI
- * where std VESA representation will not
- * pass constraint V_FRONT_PORCH >=
- * V_REF_TO_SYNC + 1.So reload mode in
- * CVT timing standards.
- */
- if (!tegra_dc_reload_mode(mode))
- return false;
- }
- else
- memcpy(mode, supported_mode, sizeof(*mode));
+ /* Check if the mode's pixel clock is more than the max rate*/
+ if (!tegra_dc_hdmi_valid_pixclock(dc, mode))
+ return false;
- mode->flag = FB_MODE_IS_DETAILED;
- clock_per_frame = tegra_dc_calc_clock_per_frame(mode);
- mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000)
- / clock_per_frame;
- return true;
+ /* Check if the mode's aspect ratio is supported */
+ if (!tegra_dc_hdmi_valid_asp_ratio(dc, mode))
+ return false;
+
+ /* Check some of DC's constraints */
+ if (mode->hsync_len > 1 && mode->vsync_len > 1 &&
+ mode->lower_margin + mode->vsync_len + mode->upper_margin > 1 &&
+ mode->xres >= 16 && mode->yres >= 16) {
+
+ if (mode->lower_margin == 1) {
+ /* This might be the case for HDMI<->DVI
+ * where std VESA representation will not
+ * pass constraint V_FRONT_PORCH >=
+ * V_REF_TO_SYNC + 1.So reload mode in
+ * CVT timing standards.
+ */
+ if (!tegra_dc_reload_mode(mode))
+ return false;
}
+ mode->flag = FB_MODE_IS_DETAILED;
+ mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000) /
+ tegra_dc_calc_clock_per_frame(mode);
+ return true;
}
return false;
}
-
static bool tegra_dc_hdmi_hpd(struct tegra_dc *dc)
{
- int sense;
- int level;
-
- level = gpio_get_value(dc->out->hotplug_gpio);
-
- sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK;
-
- return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) ||
- (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level);
+ return tegra_dc_hpd(dc);
}
@@ -1816,7 +1865,10 @@ static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc, unsigned audio_freq,
a_source = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF;
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
- tegra_hdmi_writel(hdmi,a_source | AUDIO_CNTRL0_INJECT_NULLSMPL,
+ if (hdmi->audio_inject_null)
+ a_source |= AUDIO_CNTRL0_INJECT_NULLSMPL;
+
+ tegra_hdmi_writel(hdmi,a_source,
HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
tegra_hdmi_writel(hdmi,
AUDIO_CNTRL0_ERROR_TOLERANCE(6) |
@@ -1919,6 +1971,31 @@ int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_sourc
EXPORT_SYMBOL(tegra_hdmi_setup_audio_freq_source);
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+int tegra_hdmi_audio_null_sample_inject(bool on)
+{
+ struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
+ unsigned int val = 0;
+
+ if (!hdmi)
+ return -EAGAIN;
+
+ if (hdmi->audio_inject_null != on) {
+ hdmi->audio_inject_null = on;
+ if (hdmi->clk_enabled) {
+ val = tegra_hdmi_readl(hdmi,
+ HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
+ val &= ~AUDIO_CNTRL0_INJECT_NULLSMPL;
+ if (on)
+ val |= AUDIO_CNTRL0_INJECT_NULLSMPL;
+ tegra_hdmi_writel(hdmi,val,
+ HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_hdmi_audio_null_sample_inject);
+
int tegra_hdmi_setup_hda_presence()
{
struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
@@ -2005,6 +2082,11 @@ static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
avi.r = HDMI_AVI_R_SAME;
+ if ((dc->mode.h_active == 720) && ((dc->mode.v_active == 480) || (dc->mode.v_active == 576)))
+ tegra_dc_writel(dc, 0x00101010, DC_DISP_BORDER_COLOR);
+ else
+ tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
+
if (dc->mode.v_active == 480) {
if (dc->mode.h_active == 640) {
avi.m = HDMI_AVI_M_4_3;
@@ -2037,9 +2119,12 @@ static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
(dc->mode.v_active == 2205 && dc->mode.stereo_mode)) {
/* VIC for both 1080p and 1080p 3D mode */
avi.m = HDMI_AVI_M_16_9;
- if (dc->mode.h_front_porch == 88)
- avi.vic = 16; /* 60 Hz */
- else if (dc->mode.h_front_porch == 528)
+ if (dc->mode.h_front_porch == 88) {
+ if (dc->mode.pclk > 74250000)
+ avi.vic = 16; /* 60 Hz */
+ else
+ avi.vic = 34; /* 30 Hz */
+ } else if (dc->mode.h_front_porch == 528)
avi.vic = 31; /* 50 Hz */
else
avi.vic = 32; /* 24 Hz */
@@ -2200,10 +2285,16 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
VSYNC_WINDOW_ENABLE,
HDMI_NV_PDISP_HDMI_VSYNC_WINDOW);
- tegra_hdmi_writel(hdmi,
- (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
- ARM_VIDEO_RANGE_LIMITED,
- HDMI_NV_PDISP_INPUT_CONTROL);
+ if ((dc->mode.h_active == 720) && ((dc->mode.v_active == 480) || (dc->mode.v_active == 576)))
+ tegra_hdmi_writel(hdmi,
+ (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
+ ARM_VIDEO_RANGE_FULL,
+ HDMI_NV_PDISP_INPUT_CONTROL);
+ else
+ tegra_hdmi_writel(hdmi,
+ (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
+ ARM_VIDEO_RANGE_LIMITED,
+ HDMI_NV_PDISP_INPUT_CONTROL);
clk_disable(hdmi->disp1_clk);
clk_disable(hdmi->disp2_clk);
@@ -2374,6 +2465,7 @@ struct tegra_dc_out_ops tegra_dc_hdmi_ops = {
.detect = tegra_dc_hdmi_detect,
.suspend = tegra_dc_hdmi_suspend,
.resume = tegra_dc_hdmi_resume,
+ .mode_filter = tegra_dc_hdmi_mode_filter,
};
struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc)
diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c
index 2112643058f4..47d4e69cab2e 100644
--- a/drivers/video/tegra/dc/rgb.c
+++ b/drivers/video/tegra/dc/rgb.c
@@ -90,7 +90,7 @@ static const u32 tegra_dc_rgb_disable_pintable[] = {
DC_COM_PIN_OUTPUT_SELECT6, 0x00000000,
};
-void tegra_dc_rgb_enable(struct tegra_dc *dc)
+static void tegra_dc_rgb_enable(struct tegra_dc *dc)
{
int i;
u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)];
@@ -144,9 +144,13 @@ void tegra_dc_rgb_enable(struct tegra_dc *dc)
}
tegra_dc_write_table(dc, out_sel_pintable);
+
+ /* Inform DC register updated */
+ tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
}
-void tegra_dc_rgb_disable(struct tegra_dc *dc)
+static void tegra_dc_rgb_disable(struct tegra_dc *dc)
{
tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index e24588bdd0b7..50aa9b383059 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -6,7 +6,7 @@
* Colin Cross <ccross@android.com>
* Travis Geiselbrecht <travis@palm.com>
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (C) 2010-2011 NVIDIA Corporation
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -37,7 +37,7 @@
#include <mach/dc.h>
#include <mach/fb.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "host/dev.h"
#include "nvmap/nvmap.h"
@@ -64,11 +64,27 @@ static u32 pseudo_palette[16];
static int tegra_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
+ struct tegra_fb_info *tegra_fb = info->par;
+ struct tegra_dc *dc = tegra_fb->win->dc;
+ struct tegra_dc_out_ops *ops = dc->out_ops;
+ struct fb_videomode mode;
+
if ((var->yres * var->xres * var->bits_per_pixel / 8 * 2) >
info->screen_size)
return -EINVAL;
- /* double yres_virtual to allow double buffering through pan_display */
+ /* Apply mode filter for HDMI only -LVDS supports only fix mode */
+ if (ops && ops->mode_filter) {
+
+ fb_var_to_videomode(&mode, var);
+ if (!ops->mode_filter(dc, &mode))
+ return -EINVAL;
+
+ /* Mode filter may have modified the mode */
+ fb_videomode_to_var(var, &mode);
+ }
+
+ /* Double yres_virtual to allow double buffering through pan_display */
var->yres_virtual = var->yres * 2;
return 0;
@@ -79,10 +95,6 @@ static int tegra_fb_set_par(struct fb_info *info)
struct tegra_fb_info *tegra_fb = info->par;
struct fb_var_screeninfo *var = &info->var;
- BUG_ON(info == NULL);
- if (!info)
- return -EINVAL;
-
if (var->bits_per_pixel) {
/* we only support RGB ordering for now */
switch (var->bits_per_pixel) {
@@ -287,16 +299,6 @@ static int tegra_fb_blank(int blank, struct fb_info *info)
dev_dbg(&tegra_fb->ndev->dev, "unblank\n");
tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
tegra_dc_enable(tegra_fb->win->dc);
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
- /*
- * TODO:
- * This is a work around to provide an unblanking flip
- * to dc driver, required to display fb-console after
- * a blank event,and needs to be replaced by a proper
- * unblanking mechanism
- */
- tegra_fb_flip_win(tegra_fb);
-#endif
return 0;
case FB_BLANK_NORMAL:
@@ -335,7 +337,8 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
(var->xoffset * (var->bits_per_pixel/8));
tegra_fb->win->phys_addr = addr;
- /* TODO: update virt_addr */
+ tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
+ tegra_fb->win->virt_addr = info->screen_base;
tegra_dc_update_windows(&tegra_fb->win, 1);
tegra_dc_sync_windows(&tegra_fb->win, 1);
@@ -524,7 +527,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
unsigned long fb_size = 0;
unsigned long fb_phys = 0;
int ret = 0;
- struct fb_videomode m;
win = tegra_dc_get_window(dc, fb_data->win);
if (!win) {
@@ -576,15 +578,22 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->fix.line_length = round_up(info->fix.line_length,
TEGRA_LINEAR_PITCH_ALIGNMENT);
- INIT_LIST_HEAD(&info->modelist);
- tegra_dc_to_fb_videomode(&m, &dc->mode);
- fb_videomode_to_var(&info->var, &m);
+ info->var.xres = fb_data->xres;
+ info->var.yres = fb_data->yres;
info->var.xres_virtual = fb_data->xres;
info->var.yres_virtual = fb_data->yres * 2;
info->var.bits_per_pixel = fb_data->bits_per_pixel;
info->var.activate = FB_ACTIVATE_VBL;
info->var.height = tegra_dc_get_out_height(dc);
info->var.width = tegra_dc_get_out_width(dc);
+ info->var.pixclock = 0;
+ info->var.left_margin = 0;
+ info->var.right_margin = 0;
+ info->var.upper_margin = 0;
+ info->var.lower_margin = 0;
+ info->var.hsync_len = 0;
+ info->var.vsync_len = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
win->x.full = dfixed_const(0);
win->y.full = dfixed_const(0);
diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile
index 0180885af4d7..d47c97571286 100644
--- a/drivers/video/tegra/host/Makefile
+++ b/drivers/video/tegra/host/Makefile
@@ -9,7 +9,8 @@ nvhost-objs = \
bus.o \
dev.o \
debug.o \
- bus_client.o
+ bus_client.o \
+ chip_support.o
obj-$(CONFIG_TEGRA_GRHOST) += mpe/
obj-$(CONFIG_TEGRA_GRHOST) += gr3d/
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
index 774aac7bd431..e59dc4153b14 100644
--- a/drivers/video/tegra/host/bus.c
+++ b/drivers/video/tegra/host/bus.c
@@ -17,11 +17,14 @@
*
*/
+#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/nvhost.h>
+#include "bus.h"
#include "dev.h"
+struct nvhost_bus *nvhost_bus_inst;
struct nvhost_master *nvhost;
struct resource *nvhost_get_resource(struct nvhost_device *dev,
@@ -72,12 +75,42 @@ int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
}
EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
+static struct nvhost_device_id *nvhost_bus_match_id(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
+{
+ while (id_table->name[0]) {
+ if (strcmp(dev->name, id_table->name) == 0)
+ return id_table;
+ id_table++;
+ }
+ return NULL;
+}
+
+static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
+{
+ struct nvhost_device *dev = to_nvhost_device(_dev);
+ struct nvhost_driver *ndrv = to_nvhost_driver(drv);
+
+ /* check if driver support multiple devices through id_table */
+ if (ndrv->id_table)
+ return nvhost_bus_match_id(dev, ndrv->id_table) != NULL;
+ else /* driver does not support id_table */
+ return !strncmp(dev->name, drv->name, strlen(drv->name));
+}
+
static int nvhost_drv_probe(struct device *_dev)
{
struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
struct nvhost_device *dev = to_nvhost_device(_dev);
- return drv->probe(dev);
+ if (drv && drv->probe) {
+ if (drv->id_table)
+ return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table));
+ else
+ return drv->probe(dev, NULL);
+ }
+ else
+ return -ENODEV;
}
static int nvhost_drv_remove(struct device *_dev)
@@ -98,7 +131,7 @@ static void nvhost_drv_shutdown(struct device *_dev)
int nvhost_driver_register(struct nvhost_driver *drv)
{
- drv->driver.bus = &nvhost_bus_type;
+ drv->driver.bus = &nvhost_bus_inst->nvhost_bus_type;
if (drv->probe)
drv->driver.probe = nvhost_drv_probe;
if (drv->remove)
@@ -129,7 +162,7 @@ int nvhost_device_register(struct nvhost_device *dev)
if (!dev->dev.parent && nvhost && nvhost->dev != dev)
dev->dev.parent = &nvhost->dev->dev;
- dev->dev.bus = &nvhost_bus_type;
+ dev->dev.bus = &nvhost_bus_inst->nvhost_bus_type;
if (dev->id != -1)
dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
@@ -194,13 +227,6 @@ void nvhost_device_unregister(struct nvhost_device *dev)
}
EXPORT_SYMBOL_GPL(nvhost_device_unregister);
-static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
-{
- struct nvhost_device *dev = to_nvhost_device(_dev);
-
- return !strncmp(dev->name, drv->name, strlen(drv->name));
-}
-
#ifdef CONFIG_PM_SLEEP
static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
@@ -528,13 +554,6 @@ static const struct dev_pm_ops nvhost_dev_pm_ops = {
.runtime_idle = nvhost_pm_runtime_idle,
};
-struct bus_type nvhost_bus_type = {
- .name = "nvhost",
- .match = nvhost_bus_match,
- .pm = &nvhost_dev_pm_ops,
-};
-EXPORT_SYMBOL(nvhost_bus_type);
-
static int set_parent(struct device *dev, void *data)
{
struct nvhost_device *ndev = to_nvhost_device(dev);
@@ -549,21 +568,44 @@ int nvhost_bus_add_host(struct nvhost_master *host)
nvhost = host;
/* Assign host1x as parent to all devices in nvhost bus */
- bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
+ bus_for_each_dev(&nvhost_bus_inst->nvhost_bus_type, NULL, host, set_parent);
return 0;
}
+struct nvhost_bus *nvhost_bus_get(void)
+{
+ return nvhost_bus_inst;
+}
int nvhost_bus_init(void)
{
int err;
+ struct nvhost_chip_support *chip_ops;
pr_info("host1x bus init\n");
- err = bus_register(&nvhost_bus_type);
+ nvhost_bus_inst = kzalloc(sizeof(*nvhost_bus_inst), GFP_KERNEL);
+ if (nvhost_bus_inst == NULL) {
+ pr_err("%s: Cannot allocate nvhost_bus\n", __func__);
+ return -ENOMEM;
+ }
+
+ chip_ops = kzalloc(sizeof(*chip_ops), GFP_KERNEL);
+ if (chip_ops == NULL) {
+ pr_err("%s: Cannot allocate nvhost_chip_support\n", __func__);
+ kfree(nvhost_bus_inst);
+ nvhost_bus_inst = NULL;
+ return -ENOMEM;
+ }
+
+ nvhost_bus_inst->nvhost_bus_type.name = "nvhost";
+ nvhost_bus_inst->nvhost_bus_type.match = nvhost_bus_match;
+ nvhost_bus_inst->nvhost_bus_type.pm = &nvhost_dev_pm_ops;
+ nvhost_bus_inst->nvhost_chip_ops = chip_ops;
+
+ err = bus_register(&nvhost_bus_inst->nvhost_bus_type);
return err;
}
postcore_initcall(nvhost_bus_init);
-
diff --git a/drivers/video/tegra/host/bus.h b/drivers/video/tegra/host/bus.h
new file mode 100644
index 000000000000..99f820335d60
--- /dev/null
+++ b/drivers/video/tegra/host/bus.h
@@ -0,0 +1,38 @@
+/*
+ * drivers/video/tegra/host/bus.h
+ *
+ * Tegra Graphics Host bus API header
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * 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/>.
+ */
+
+#ifndef __NVHOST_BUS_H
+#define __NVHOST_BUS_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include "chip_support.h"
+
+struct nvhost_bus {
+ struct nvhost_chip_support *nvhost_chip_ops;
+ struct bus_type nvhost_bus_type;
+};
+
+struct nvhost_bus *nvhost_bus_get(void);
+
+extern struct nvhost_bus *nvhost_bus_inst;
+
+#endif
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index b49c26e04f29..fd632a6ea9c5 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -36,7 +36,7 @@
#include <linux/nvhost.h>
#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <mach/iomap.h>
@@ -44,6 +44,11 @@
#include "debug.h"
#include "bus_client.h"
#include "dev.h"
+#include "nvhost_acm.h"
+
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
void nvhost_read_module_regs(struct nvhost_device *ndev,
u32 offset, int count, u32 *values)
@@ -85,45 +90,6 @@ struct nvhost_channel_userctx {
int clientid;
};
-/*
- * Write cmdbuf to ftrace output. Checks if cmdbuf contents should be output
- * and mmaps the cmdbuf contents if required.
- */
-static void trace_write_cmdbufs(struct nvhost_job *job)
-{
- struct nvmap_handle_ref handle;
- void *mem = NULL;
- int i = 0;
-
- for (i = 0; i < job->num_gathers; i++) {
- struct nvhost_channel_gather *gather = &job->gathers[i];
- if (nvhost_debug_trace_cmdbuf) {
- handle.handle = nvmap_id_to_handle(gather->mem_id);
- mem = nvmap_mmap(&handle);
- if (IS_ERR_OR_NULL(mem))
- mem = NULL;
- };
-
- if (mem) {
- u32 i;
- /*
- * Write in batches of 128 as there seems to be a limit
- * of how much you can output to ftrace at once.
- */
- for (i = 0; i < gather->words; i += TRACE_MAX_LENGTH) {
- trace_nvhost_channel_write_cmdbuf_data(
- job->ch->dev->name,
- gather->mem_id,
- min(gather->words - i,
- TRACE_MAX_LENGTH),
- gather->offset + i * sizeof(u32),
- mem);
- }
- nvmap_munmap(&handle, mem);
- }
- }
-}
-
static int nvhost_channelrelease(struct inode *inode, struct file *filp)
{
struct nvhost_channel_userctx *priv = filp->private_data;
@@ -174,6 +140,7 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
priv->priority = NVHOST_PRIORITY_MEDIUM;
priv->clientid = atomic_add_return(1,
&nvhost_get_host(ch->dev)->clientid);
+ priv->timeout = MAX_STUCK_CHECK_COUNT * SYNCPT_CHECK_PERIOD;
priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
NULL, priv->priority, priv->clientid);
@@ -364,8 +331,6 @@ static int nvhost_ioctl_channel_flush(
ctx->timeout = nvhost_debug_force_timeout_val;
}
- trace_write_cmdbufs(ctx->job);
-
/* context switch if needed, and submit user's gathers to the channel */
err = nvhost_channel_submit(ctx->job);
args->value = ctx->job->syncpt_end;
@@ -375,12 +340,11 @@ static int nvhost_ioctl_channel_flush(
return err;
}
-static int nvhost_ioctl_channel_read_3d_reg(
- struct nvhost_channel_userctx *ctx,
+static int nvhost_ioctl_channel_read_3d_reg(struct nvhost_channel_userctx *ctx,
struct nvhost_read_3d_reg_args *args)
{
- BUG_ON(!channel_op(ctx->ch).read3dreg);
- return channel_op(ctx->ch).read3dreg(ctx->ch, ctx->hwctx,
+ BUG_ON(!channel_op().read3dreg);
+ return channel_op().read3dreg(ctx->ch, ctx->hwctx,
args->offset, &args->value);
}
@@ -535,18 +499,23 @@ int nvhost_client_user_init(struct nvhost_device *dev)
int err, devno;
struct nvhost_channel *ch = dev->channel;
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
+ if (err < 0) {
+ dev_err(&dev->dev, "failed to allocate devno\n");
+ goto fail;
+ }
cdev_init(&ch->cdev, &nvhost_channelops);
ch->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + dev->index);
err = cdev_add(&ch->cdev, devno, 1);
if (err < 0) {
dev_err(&dev->dev,
"failed to add chan %i cdev\n", dev->index);
goto fail;
}
- ch->node = device_create(nvhost_get_host(dev)->nvhost_class, NULL, devno, NULL,
+ ch->node = device_create(nvhost_get_host(dev)->nvhost_class,
+ NULL, devno, NULL,
IFACE_NAME "-%s", dev->name);
if (IS_ERR(ch->node)) {
err = PTR_ERR(ch->node);
@@ -564,7 +533,11 @@ int nvhost_client_device_init(struct nvhost_device *dev)
{
int err;
struct nvhost_master *nvhost_master = nvhost_get_host(dev);
- struct nvhost_channel *ch = &nvhost_master->channels[dev->index];
+ struct nvhost_channel *ch;
+
+ ch = nvhost_alloc_channel(dev->index);
+ if (ch == NULL)
+ return -ENODEV;
/* store the pointer to this device for channel */
ch->dev = dev;
@@ -587,6 +560,7 @@ int nvhost_client_device_init(struct nvhost_device *dev)
fail:
/* Add clean-up */
+ nvhost_free_channel(ch);
return err;
}
diff --git a/drivers/video/tegra/host/chip_support.c b/drivers/video/tegra/host/chip_support.c
new file mode 100644
index 000000000000..9abb1fa026a4
--- /dev/null
+++ b/drivers/video/tegra/host/chip_support.c
@@ -0,0 +1,56 @@
+/*
+ * drivers/video/tegra/host/chip_support.c
+ *
+ * Tegra Graphics Host Chip support module
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * 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/errno.h>
+
+#include <mach/hardware.h>
+
+#include "bus.h"
+#include "chip_support.h"
+#include "t20/t20.h"
+#include "t30/t30.h"
+
+struct nvhost_chip_support *nvhost_get_chip_ops(void)
+{
+ return (nvhost_bus_get())->nvhost_chip_ops;
+}
+
+int nvhost_init_chip_support(struct nvhost_master *host)
+{
+ int err = 0;
+ struct nvhost_chip_support *chip_ops;
+
+ chip_ops = nvhost_get_chip_ops();
+
+ switch (tegra_get_chipid()) {
+ case TEGRA_CHIPID_TEGRA2:
+ err = nvhost_init_t20_support(host, chip_ops);
+ break;
+
+ case TEGRA_CHIPID_TEGRA3:
+ err = nvhost_init_t30_support(host, chip_ops);
+ break;
+
+ default:
+ err = -ENODEV;
+ }
+
+ return err;
+}
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
index 6727e7a69fb4..edc5f6a51574 100644
--- a/drivers/video/tegra/host/chip_support.h
+++ b/drivers/video/tegra/host/chip_support.h
@@ -21,21 +21,26 @@
#define _NVHOST_CHIP_SUPPORT_H_
#include <linux/types.h>
+#include "bus.h"
+
struct output;
+
+struct nvhost_master;
+struct nvhost_intr;
+struct nvhost_syncpt;
struct nvhost_waitchk;
struct nvhost_userctx_timeout;
-struct nvhost_master;
struct nvhost_channel;
struct nvmap_handle;
struct nvmap_client;
struct nvhost_hwctx;
struct nvhost_cdma;
-struct nvhost_intr;
+struct nvhost_job;
struct push_buffer;
struct nvhost_syncpt;
-struct nvhost_master;
struct dentry;
struct nvhost_job;
+struct nvhost_intr_syncpt;
struct nvhost_chip_support {
struct {
@@ -64,11 +69,6 @@ struct nvhost_chip_support {
u32 syncpt_incrs,
u32 syncval,
u32 nr_slots);
- void (*timeout_pb_incr)(struct nvhost_cdma *,
- u32 getptr,
- u32 syncpt_incrs,
- u32 nr_slots,
- bool exec_ctxsave);
} cdma;
struct {
@@ -133,9 +133,22 @@ struct nvhost_chip_support {
} intr;
struct {
- struct nvhost_device *(*get_nvhost_device)(struct nvhost_master *host,
- char *name);
+ struct nvhost_device *(*get_nvhost_device)(char *name);
+ struct nvhost_channel *(*alloc_nvhost_channel)(int chid);
+ void (*free_nvhost_channel)(struct nvhost_channel *ch);
} nvhost_dev;
};
+struct nvhost_chip_support *nvhost_get_chip_ops(void);
+
+#define host_device_op() nvhost_get_chip_ops()->nvhost_dev
+#define channel_cdma_op() nvhost_get_chip_ops()->cdma
+#define channel_op() nvhost_get_chip_ops()->channel
+#define syncpt_op() nvhost_get_chip_ops()->syncpt
+#define intr_op() nvhost_get_chip_ops()->intr
+#define cdma_op() nvhost_get_chip_ops()->cdma
+#define cdma_pb_op() nvhost_get_chip_ops()->push_buffer
+
+int nvhost_init_chip_support(struct nvhost_master *);
+
#endif /* _NVHOST_CHIP_SUPPORT_H_ */
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index 91436c903fc6..8a26f92c79f6 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -22,8 +22,12 @@
#include <linux/io.h>
+#include "bus.h"
#include "dev.h"
#include "debug.h"
+#include "nvhost_acm.h"
+#include "nvhost_channel.h"
+#include "chip_support.h"
pid_t nvhost_debug_null_kickoff_pid;
unsigned int nvhost_debug_trace_cmdbuf;
@@ -59,8 +63,8 @@ static int show_channels(struct device *dev, void *data)
mutex_lock(&ch->reflock);
if (ch->refcount) {
mutex_lock(&ch->cdma.lock);
- m->op.debug.show_channel_fifo(m, ch, o, nvdev->index);
- m->op.debug.show_channel_cdma(m, ch, o, nvdev->index);
+ nvhost_get_chip_ops()->debug.show_channel_fifo(m, ch, o, nvdev->index);
+ nvhost_get_chip_ops()->debug.show_channel_cdma(m, ch, o, nvdev->index);
mutex_unlock(&ch->cdma.lock);
}
mutex_unlock(&ch->reflock);
@@ -72,7 +76,7 @@ static int show_channels(struct device *dev, void *data)
static void show_syncpts(struct nvhost_master *m, struct output *o)
{
int i;
- BUG_ON(!m->op.syncpt.name);
+ BUG_ON(!nvhost_get_chip_ops()->syncpt.name);
nvhost_debug_output(o, "---- syncpts ----\n");
for (i = 0; i < m->syncpt.nb_pts; i++) {
u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
@@ -80,7 +84,7 @@ static void show_syncpts(struct nvhost_master *m, struct output *o)
if (!min && !max)
continue;
nvhost_debug_output(o, "id %d (%s) min %d max %d\n",
- i, m->op.syncpt.name(&m->syncpt, i),
+ i, nvhost_get_chip_ops()->syncpt.name(&m->syncpt, i),
min, max);
}
@@ -99,10 +103,10 @@ static void show_all(struct nvhost_master *m, struct output *o)
{
nvhost_module_busy(m->dev);
- m->op.debug.show_mlocks(m, o);
+ nvhost_get_chip_ops()->debug.show_mlocks(m, o);
show_syncpts(m, o);
nvhost_debug_output(o, "---- channels ----\n");
- bus_for_each_dev(&nvhost_bus_type, NULL, o, show_channels);
+ bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o, show_channels);
nvhost_module_idle(m->dev);
}
@@ -142,8 +146,8 @@ void nvhost_debug_init(struct nvhost_master *master)
debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
&nvhost_debug_trace_cmdbuf);
- if (master->op.debug.debug_init)
- master->op.debug.debug_init(de);
+ if (nvhost_get_chip_ops()->debug.debug_init)
+ nvhost_get_chip_ops()->debug.debug_init(de);
debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
&nvhost_debug_force_timeout_pid);
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index 2e1ffeea7729..ca73528fbeeb 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -36,22 +36,21 @@
#include <linux/nvhost.h>
#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <mach/iomap.h>
#include "debug.h"
-#include "nvhost_job.h"
#include "t20/t20.h"
#include "t30/t30.h"
#include "bus_client.h"
+#include "nvhost_acm.h"
+#include <linux/nvmap.h>
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
#define DRIVER_NAME "host1x"
-int nvhost_major;
-int nvhost_minor;
-
static unsigned int register_sets;
struct nvhost_ctrl_userctx {
@@ -79,7 +78,8 @@ static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
{
- struct nvhost_master *host = container_of(inode->i_cdev, struct nvhost_master, cdev);
+ struct nvhost_master *host =
+ container_of(inode->i_cdev, struct nvhost_master, cdev);
struct nvhost_ctrl_userctx *priv;
u32 *mod_locks;
@@ -167,24 +167,21 @@ static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
return err;
}
-static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
- u32 id)
+static int match_by_moduleid(struct device *dev, void *data)
{
- int i;
+ struct nvhost_device *ndev = to_nvhost_device(dev);
+ u32 id = (u32)data;
- for (i = 0; i < host->nb_channels; i++) {
- struct nvhost_device *ndev = host->channels[i].dev;
+ return id == ndev->moduleid;
+}
- /* display and dsi do not use channel for register programming.
- * so their channels do not have device instance.
- * hence skip such channels from here. */
- if (ndev == NULL)
- continue;
+static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
+ u32 id)
+{
+ struct device *dev = bus_find_device(&nvhost_bus_inst->nvhost_bus_type, NULL, (void *)id,
+ match_by_moduleid);
- if (id == ndev->moduleid)
- return ndev;
- }
- return NULL;
+ return dev ? to_nvhost_device(dev) : NULL;
}
static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
@@ -329,9 +326,7 @@ static int __devinit nvhost_user_init(struct nvhost_master *host)
goto fail;
}
- err = alloc_chrdev_region(&devno, nvhost_minor,
- host->nb_channels + 1, IFACE_NAME);
- nvhost_major = MAJOR(devno);
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
if (err < 0) {
dev_err(&host->dev->dev, "failed to reserve chrdev region\n");
goto fail;
@@ -339,7 +334,6 @@ static int __devinit nvhost_user_init(struct nvhost_master *host)
cdev_init(&host->cdev, &nvhost_ctrlops);
host->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + host->nb_channels);
err = cdev_add(&host->cdev, devno, 1);
if (err < 0)
goto fail;
@@ -358,45 +352,40 @@ fail:
struct nvhost_device *nvhost_get_device(char *name)
{
- BUG_ON(!host_device_op(nvhost).get_nvhost_device);
- return host_device_op(nvhost).get_nvhost_device(nvhost, name);
+ BUG_ON(!host_device_op().get_nvhost_device);
+ return host_device_op().get_nvhost_device(name);
}
-static void nvhost_remove_chip_support(struct nvhost_master *host)
+struct nvhost_channel *nvhost_alloc_channel(int index)
{
- kfree(host->channels);
- host->channels = 0;
+ BUG_ON(!host_device_op().alloc_nvhost_channel);
+ return host_device_op().alloc_nvhost_channel(index);
+}
+
+void nvhost_free_channel(struct nvhost_channel *ch)
+{
+ BUG_ON(!host_device_op().free_nvhost_channel);
+ host_device_op().free_nvhost_channel(ch);
+}
+static void nvhost_free_resources(struct nvhost_master *host)
+{
kfree(host->intr.syncpt);
host->intr.syncpt = 0;
}
-static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
+static int __devinit nvhost_alloc_resources(struct nvhost_master *host)
{
int err;
- switch (tegra_get_chipid()) {
- case TEGRA_CHIPID_TEGRA2:
- err = nvhost_init_t20_support(host);
- break;
-
- case TEGRA_CHIPID_TEGRA3:
- err = nvhost_init_t30_support(host);
- break;
- default:
- return -ENODEV;
- }
+ err = nvhost_init_chip_support(host);
if (err)
return err;
- /* allocate items sized in chip specific support init */
- host->channels = kzalloc(sizeof(struct nvhost_channel) *
- host->nb_channels, GFP_KERNEL);
-
host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
host->syncpt.nb_pts, GFP_KERNEL);
- if (!(host->channels && host->intr.syncpt)) {
+ if (!host->intr.syncpt) {
/* frees happen in the support removal phase */
return -ENOMEM;
}
@@ -427,13 +416,12 @@ struct nvhost_device tegra_grhost_device = {
.id = -1,
.resource = nvhost_resources,
.num_resources = ARRAY_SIZE(nvhost_resources),
- .finalize_poweron = power_on_host,
- .prepare_poweroff = power_off_host,
.clocks = {{"host1x", UINT_MAX}, {} },
NVHOST_MODULE_NO_POWERGATE_IDS,
};
-static int __devinit nvhost_probe(struct nvhost_device *dev)
+static int __devinit nvhost_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
struct nvhost_master *host;
struct resource *regs, *intr0, *intr1;
@@ -474,7 +462,7 @@ static int __devinit nvhost_probe(struct nvhost_device *dev)
goto fail;
}
- err = nvhost_init_chip_support(host);
+ err = nvhost_alloc_resources(host);
if (err) {
dev_err(&dev->dev, "failed to init chip support\n");
goto fail;
@@ -516,7 +504,7 @@ static int __devinit nvhost_probe(struct nvhost_device *dev)
return 0;
fail:
- nvhost_remove_chip_support(host);
+ nvhost_free_resources(host);
if (host->nvmap)
nvmap_client_put(host->nvmap);
kfree(host);
@@ -528,7 +516,7 @@ static int __exit nvhost_remove(struct nvhost_device *dev)
struct nvhost_master *host = nvhost_get_drvdata(dev);
nvhost_intr_deinit(&host->intr);
nvhost_syncpt_deinit(&host->syncpt);
- nvhost_remove_chip_support(host);
+ nvhost_free_resources(host);
return 0;
}
@@ -557,7 +545,9 @@ static struct nvhost_driver nvhost_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME
- }
+ },
+ .finalize_poweron = power_on_host,
+ .prepare_poweroff = power_off_host,
};
static int __init nvhost_mod_init(void)
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
index 74d7e16fc272..41c4fb59b264 100644
--- a/drivers/video/tegra/host/dev.h
+++ b/drivers/video/tegra/host/dev.h
@@ -21,19 +21,16 @@
#ifndef __NVHOST_DEV_H
#define __NVHOST_DEV_H
-#include "nvhost_acm.h"
+#include <linux/cdev.h>
#include "nvhost_syncpt.h"
#include "nvhost_intr.h"
-#include "nvhost_channel.h"
#include "chip_support.h"
#define TRACE_MAX_LENGTH 128U
#define IFACE_NAME "nvhost"
-extern int nvhost_major;
-extern int nvhost_minor;
-
struct nvhost_hwctx;
+struct nvhost_channel;
struct nvhost_master {
void __iomem *aperture;
@@ -46,11 +43,6 @@ struct nvhost_master {
struct nvmap_client *nvmap;
struct nvhost_intr intr;
struct nvhost_device *dev;
- struct nvhost_channel *channels;
- u32 nb_channels;
-
- struct nvhost_chip_support op;
-
atomic_t clientid;
};
@@ -59,9 +51,9 @@ extern struct nvhost_master *nvhost;
void nvhost_debug_init(struct nvhost_master *master);
void nvhost_debug_dump(struct nvhost_master *master);
-#define host_device_op(host) (host->op.nvhost_dev)
-
struct nvhost_device *nvhost_get_device(char *name);
+struct nvhost_channel *nvhost_alloc_channel(int index);
+void nvhost_free_channel(struct nvhost_channel *ch);
extern pid_t nvhost_debug_null_kickoff_pid;
diff --git a/drivers/video/tegra/host/dsi/dsi.c b/drivers/video/tegra/host/dsi/dsi.c
index 0e49f591574d..87da8a6f1b8a 100644
--- a/drivers/video/tegra/host/dsi/dsi.c
+++ b/drivers/video/tegra/host/dsi/dsi.c
@@ -21,7 +21,8 @@
#include "dev.h"
#include "bus_client.h"
-static int dsi_probe(struct nvhost_device *dev)
+static int dsi_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
return nvhost_client_device_init(dev);
}
diff --git a/drivers/video/tegra/host/gr2d/gr2d.c b/drivers/video/tegra/host/gr2d/gr2d.c
index f88eb72e0a40..c91a3aa23714 100644
--- a/drivers/video/tegra/host/gr2d/gr2d.c
+++ b/drivers/video/tegra/host/gr2d/gr2d.c
@@ -21,7 +21,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit gr2d_probe(struct nvhost_device *dev)
+static int __devinit gr2d_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
return nvhost_client_device_init(dev);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d.c b/drivers/video/tegra/host/gr3d/gr3d.c
index f387d54e585e..b621a47bf650 100644
--- a/drivers/video/tegra/host/gr3d/gr3d.c
+++ b/drivers/video/tegra/host/gr3d/gr3d.c
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/slab.h>
#include "t20/t20.h"
@@ -28,7 +28,13 @@
#include "nvhost_hwctx.h"
#include "dev.h"
#include "gr3d.h"
+#include "gr3d_t20.h"
+#include "gr3d_t30.h"
+#include "scale3d.h"
#include "bus_client.h"
+#include "nvhost_channel.h"
+
+#include <mach/hardware.h>
#ifndef TEGRA_POWERGATE_3D1
#define TEGRA_POWERGATE_3D1 -1
@@ -68,7 +74,6 @@ void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
}
/*** ctx3d ***/
-
struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
struct nvhost_channel *ch, bool map_restore)
{
@@ -150,8 +155,75 @@ int nvhost_gr3d_prepare_power_off(struct nvhost_device *dev)
return host1x_save_context(dev, NVSYNCPT_3D);
}
-static int __devinit gr3d_probe(struct nvhost_device *dev)
+enum gr3d_ip_ver {
+ gr3d_01,
+ gr3d_02,
+};
+
+struct gr3d_desc {
+ void (*finalize_poweron)(struct nvhost_device *dev);
+ void (*busy)(struct nvhost_device *);
+ void (*idle)(struct nvhost_device *);
+ void (*suspend_ndev)(struct nvhost_device *);
+ void (*init)(struct nvhost_device *dev);
+ void (*deinit)(struct nvhost_device *dev);
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
+};
+
+static const struct gr3d_desc gr3d[] = {
+ [gr3d_01] = {
+ .finalize_poweron = NULL,
+ .busy = NULL,
+ .idle = NULL,
+ .suspend_ndev = NULL,
+ .init = NULL,
+ .deinit = NULL,
+ .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
+ },
+ [gr3d_02] = {
+ .finalize_poweron = NULL,
+ .busy = nvhost_scale3d_notify_busy,
+ .idle = nvhost_scale3d_notify_idle,
+ .suspend_ndev = nvhost_scale3d_suspend,
+ .init = nvhost_scale3d_init,
+ .deinit = nvhost_scale3d_deinit,
+ .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
+ },
+};
+
+static struct nvhost_device_id gr3d_id[] = {
+ { "gr3d01", gr3d_01 },
+ { "gr3d02", gr3d_02 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(nvhost, gr3d_id);
+
+static int __devinit gr3d_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
+ int index = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ index = id_table->driver_data;
+
+ drv->finalize_poweron = gr3d[index].finalize_poweron;
+ drv->busy = gr3d[index].busy;
+ drv->idle = gr3d[index].idle;
+ drv->suspend_ndev = gr3d[index].suspend_ndev;
+ drv->init = gr3d[index].init;
+ drv->deinit = gr3d[index].deinit;
+ drv->prepare_poweroff = gr3d[index].prepare_poweroff;
+ drv->alloc_hwctx_handler = gr3d[index].alloc_hwctx_handler;
+
+ /* reset device name so that consistent device name can be
+ * found in clock tree */
+ dev->name = "gr3d";
+
return nvhost_client_device_init(dev);
}
@@ -184,7 +256,8 @@ static struct nvhost_driver gr3d_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gr3d",
- }
+ },
+ .id_table = gr3d_id,
};
static int __init gr3d_init(void)
@@ -196,8 +269,10 @@ static int __init gr3d_init(void)
return -ENXIO;
err = nvhost_device_register(gr3d_device);
- if (err)
+ if (err) {
+ pr_err("Could not register 3D device\n");
return err;
+ }
return nvhost_driver_register(&gr3d_driver);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.c b/drivers/video/tegra/host/gr3d/gr3d_t20.c
index 9ca990f89077..c0efac03b882 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t20.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.c
@@ -19,6 +19,7 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
#include "dev.h"
#include "host1x/host1x_channel.h"
#include "host1x/host1x_hardware.h"
@@ -136,8 +137,9 @@ static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
nvhost_cdma_push_gather(cdma,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_get_host(nctx->channel->dev)->nvmap,
+ p->save_buf->handle,
+ 0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
index 8ca6b7b44b9e..93d98dfa645c 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t30.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -19,6 +19,8 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
+#include "nvhost_cdma.h"
#include "dev.h"
#include "host1x/host1x_hardware.h"
#include "host1x/host1x_syncpt.h"
@@ -71,7 +73,6 @@ static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
HWCTX_REGINFO(0xa02, 10, DIRECT),
HWCTX_REGINFO(0xb04, 1, DIRECT),
HWCTX_REGINFO(0xb06, 13, DIRECT),
- HWCTX_REGINFO(0xe42, 2, DIRECT), /* HW bug workaround */
};
static const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
@@ -143,8 +144,9 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
ctx->restore_phys);
/* gather the save buffer */
nvhost_cdma_push_gather(cdma,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_get_host(nctx->channel->dev)->nvmap,
+ p->save_buf->handle,
+ 0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
}
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c
index cdd6026718b1..fcb1f05f0025 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.c
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.c
@@ -19,7 +19,9 @@
*/
#include <linux/slab.h>
+#include "nvhost_acm.h"
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
#include "dev.h"
#include "host1x_hardware.h"
@@ -66,8 +68,8 @@ static int push_buffer_init(struct push_buffer *pb)
pb->phys = 0;
pb->nvmap = NULL;
- BUG_ON(!cdma_pb_op(cdma).reset);
- cdma_pb_op(cdma).reset(pb);
+ BUG_ON(!cdma_pb_op().reset);
+ cdma_pb_op().reset(pb);
/* allocate and map pushbuffer memory */
pb->mem = nvmap_alloc(nvmap, PUSH_BUFFER_SIZE + 4, 32,
@@ -101,7 +103,7 @@ static int push_buffer_init(struct push_buffer *pb)
return 0;
fail:
- cdma_pb_op(cdma).destroy(pb);
+ cdma_pb_op().destroy(pb);
return -ENOMEM;
}
@@ -191,96 +193,25 @@ static u32 push_buffer_putptr(struct push_buffer *pb)
*/
/**
- * Init timeout and syncpt incr buffer resources
+ * Init timeout resources
*/
static int cdma_timeout_init(struct nvhost_cdma *cdma,
u32 syncpt_id)
{
- struct nvhost_master *dev = cdma_to_dev(cdma);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
- struct nvhost_channel *ch = cdma_to_channel(cdma);
- u32 i = 0;
-
if (syncpt_id == NVSYNCPT_INVALID)
return -EINVAL;
- /* allocate and map syncpt incr memory */
- sb->mem = nvmap_alloc(nvmap,
- (SYNCPT_INCR_BUFFER_SIZE_WORDS * sizeof(u32)), 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
- if (IS_ERR_OR_NULL(sb->mem)) {
- sb->mem = NULL;
- goto fail;
- }
- sb->mapped = nvmap_mmap(sb->mem);
- if (sb->mapped == NULL)
- goto fail;
-
- /* pin syncpt buffer and get physical address */
- sb->phys = nvmap_pin(nvmap, sb->mem);
- if (sb->phys >= 0xfffff000) {
- sb->phys = 0;
- goto fail;
- }
-
- dev_dbg(&dev->dev->dev, "%s: SYNCPT_INCR buffer at 0x%x\n",
- __func__, sb->phys);
-
- sb->words_per_incr = (syncpt_id == NVSYNCPT_3D) ? 5 : 3;
- sb->incr_per_buffer = (SYNCPT_INCR_BUFFER_SIZE_WORDS /
- sb->words_per_incr);
-
- /* init buffer with SETCL and INCR_SYNCPT methods */
- while (i < sb->incr_per_buffer) {
- sb->mapped[i++] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- 0, 0);
- sb->mapped[i++] = nvhost_opcode_imm_incr_syncpt(
- NV_SYNCPT_IMMEDIATE,
- syncpt_id);
- if (syncpt_id == NVSYNCPT_3D) {
- /* also contains base increments */
- sb->mapped[i++] = nvhost_opcode_nonincr(
- NV_CLASS_HOST_INCR_SYNCPT_BASE,
- 1);
- sb->mapped[i++] = nvhost_class_host_incr_syncpt_base(
- NVWAITBASE_3D, 1);
- }
- sb->mapped[i++] = nvhost_opcode_setclass(ch->dev->class,
- 0, 0);
- }
- wmb();
-
INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler);
cdma->timeout.initialized = true;
return 0;
-fail:
- cdma_op(cdma).timeout_destroy(cdma);
- return -ENOMEM;
}
/**
- * Clean up timeout syncpt buffer resources
+ * Clean up timeout resources
*/
static void cdma_timeout_destroy(struct nvhost_cdma *cdma)
{
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
-
- if (sb->mapped)
- nvmap_munmap(sb->mem, sb->mapped);
-
- if (sb->phys != 0)
- nvmap_unpin(nvmap, sb->mem);
-
- if (sb->mem)
- nvmap_free(nvmap, sb->mem);
-
- sb->mem = NULL;
- sb->mapped = NULL;
- sb->phys = 0;
-
if (cdma->timeout.initialized)
cancel_delayed_work(&cdma->timeout.wq);
cdma->timeout.initialized = false;
@@ -324,73 +255,6 @@ static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
}
/**
- * This routine is called at the point we transition back into a timed
- * ctx. The syncpts are incremented via pushbuffer with a flag indicating
- * whether there's a CTXSAVE that should be still executed (for the
- * preceding HW ctx).
- */
-static void cdma_timeout_pb_incr(struct nvhost_cdma *cdma, u32 getptr,
- u32 syncpt_incrs, u32 nr_slots,
- bool exec_ctxsave)
-{
- struct nvhost_master *dev = cdma_to_dev(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
- struct push_buffer *pb = &cdma->push_buffer;
- struct host1x_hwctx *hwctx = to_host1x_hwctx(cdma->timeout.ctx);
- u32 getidx, *p;
-
- /* should have enough slots to incr to desired count */
- BUG_ON(syncpt_incrs > (nr_slots * sb->incr_per_buffer));
-
- getidx = getptr - pb->phys;
- if (exec_ctxsave) {
- /* don't disrupt the CTXSAVE of a good/non-timed out ctx */
- nr_slots -= hwctx->save_slots;
- syncpt_incrs -= hwctx->save_incrs;
-
- getidx += (hwctx->save_slots * 8);
- getidx &= (PUSH_BUFFER_SIZE - 1);
-
- dev_dbg(&dev->dev->dev,
- "%s: exec CTXSAVE of prev ctx (slots %d, incrs %d)\n",
- __func__, nr_slots, syncpt_incrs);
- }
-
- while (syncpt_incrs) {
- u32 incrs, count;
-
- /* GATHER count are incrs * number of DWORDs per incr */
- incrs = min(syncpt_incrs, sb->incr_per_buffer);
- count = incrs * sb->words_per_incr;
-
- p = (u32 *)((u32)pb->mapped + getidx);
- *(p++) = nvhost_opcode_gather(count);
- *(p++) = sb->phys;
-
- dev_dbg(&dev->dev->dev,
- "%s: GATHER at 0x%x, from 0x%x, dcount = %d\n",
- __func__,
- pb->phys + getidx, sb->phys,
- (incrs * sb->words_per_incr));
-
- syncpt_incrs -= incrs;
- getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
- nr_slots--;
- }
-
- /* NOP remaining slots */
- while (nr_slots--) {
- p = (u32 *)((u32)pb->mapped + getidx);
- *(p++) = NVHOST_OPCODE_NOOP;
- *(p++) = NVHOST_OPCODE_NOOP;
- dev_dbg(&dev->dev->dev, "%s: NOP at 0x%x\n",
- __func__, pb->phys + getidx);
- getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
- }
- wmb();
-}
-
-/**
* Start channel DMA
*/
static void cdma_start(struct nvhost_cdma *cdma)
@@ -400,8 +264,8 @@ static void cdma_start(struct nvhost_cdma *cdma)
if (cdma->running)
return;
- BUG_ON(!cdma_pb_op(cdma).putptr);
- cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ BUG_ON(!cdma_pb_op().putptr);
+ cdma->last_put = cdma_pb_op().putptr(&cdma->push_buffer);
writel(host1x_channel_dmactrl(true, false, false),
chan_regs + HOST1X_CHANNEL_DMACTRL);
@@ -435,8 +299,8 @@ static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
if (cdma->running)
return;
- BUG_ON(!cdma_pb_op(cdma).putptr);
- cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ BUG_ON(!cdma_pb_op().putptr);
+ cdma->last_put = cdma_pb_op().putptr(&cdma->push_buffer);
writel(host1x_channel_dmactrl(true, false, false),
chan_regs + HOST1X_CHANNEL_DMACTRL);
@@ -475,9 +339,9 @@ static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
static void cdma_kick(struct nvhost_cdma *cdma)
{
u32 put;
- BUG_ON(!cdma_pb_op(cdma).putptr);
+ BUG_ON(!cdma_pb_op().putptr);
- put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ put = cdma_pb_op().putptr(&cdma->push_buffer);
if (put != cdma->last_put) {
void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
@@ -629,37 +493,36 @@ static void cdma_timeout_handler(struct work_struct *work)
"%s: timeout: %d (%s) ctx 0x%p, HW thresh %d, done %d\n",
__func__,
cdma->timeout.syncpt_id,
- syncpt_op(sp).name(sp, cdma->timeout.syncpt_id),
+ syncpt_op().name(sp, cdma->timeout.syncpt_id),
cdma->timeout.ctx,
syncpt_val, cdma->timeout.syncpt_val);
/* stop HW, resetting channel/module */
- cdma_op(cdma).timeout_teardown_begin(cdma);
+ cdma_op().timeout_teardown_begin(cdma);
nvhost_cdma_update_sync_queue(cdma, sp, &dev->dev->dev);
mutex_unlock(&cdma->lock);
}
-int host1x_init_cdma_support(struct nvhost_master *host)
+int host1x_init_cdma_support(struct nvhost_chip_support *op)
{
- host->op.cdma.start = cdma_start;
- host->op.cdma.stop = cdma_stop;
- host->op.cdma.kick = cdma_kick;
-
- host->op.cdma.timeout_init = cdma_timeout_init;
- host->op.cdma.timeout_destroy = cdma_timeout_destroy;
- host->op.cdma.timeout_teardown_begin = cdma_timeout_teardown_begin;
- host->op.cdma.timeout_teardown_end = cdma_timeout_teardown_end;
- host->op.cdma.timeout_cpu_incr = cdma_timeout_cpu_incr;
- host->op.cdma.timeout_pb_incr = cdma_timeout_pb_incr;
-
- host->op.push_buffer.reset = push_buffer_reset;
- host->op.push_buffer.init = push_buffer_init;
- host->op.push_buffer.destroy = push_buffer_destroy;
- host->op.push_buffer.push_to = push_buffer_push_to;
- host->op.push_buffer.pop_from = push_buffer_pop_from;
- host->op.push_buffer.space = push_buffer_space;
- host->op.push_buffer.putptr = push_buffer_putptr;
+ op->cdma.start = cdma_start;
+ op->cdma.stop = cdma_stop;
+ op->cdma.kick = cdma_kick;
+
+ op->cdma.timeout_init = cdma_timeout_init;
+ op->cdma.timeout_destroy = cdma_timeout_destroy;
+ op->cdma.timeout_teardown_begin = cdma_timeout_teardown_begin;
+ op->cdma.timeout_teardown_end = cdma_timeout_teardown_end;
+ op->cdma.timeout_cpu_incr = cdma_timeout_cpu_incr;
+
+ op->push_buffer.reset = push_buffer_reset;
+ op->push_buffer.init = push_buffer_init;
+ op->push_buffer.destroy = push_buffer_destroy;
+ op->push_buffer.push_to = push_buffer_push_to;
+ op->push_buffer.pop_from = push_buffer_pop_from;
+ op->push_buffer.space = push_buffer_space;
+ op->push_buffer.putptr = push_buffer_putptr;
return 0;
}
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.h b/drivers/video/tegra/host/host1x/host1x_cdma.h
index 60909236a7ca..374097272d3f 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.h
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.h
@@ -36,6 +36,6 @@
* and replaces the original timed out contexts GATHER slots */
#define SYNCPT_INCR_BUFFER_SIZE_WORDS (4096 / sizeof(u32))
-int host1x_init_cdma_support(struct nvhost_master *);
+int host1x_init_cdma_support(struct nvhost_chip_support *);
#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c
index b16a34f416ab..8c4a7a5c74ad 100644
--- a/drivers/video/tegra/host/host1x/host1x_channel.c
+++ b/drivers/video/tegra/host/host1x/host1x_channel.c
@@ -20,6 +20,8 @@
#include "nvhost_channel.h"
#include "dev.h"
+#include "nvhost_acm.h"
+#include "nvhost_job.h"
#include "nvhost_hwctx.h"
#include <trace/events/nvhost.h>
#include <linux/slab.h>
@@ -142,6 +144,7 @@ static void submit_ctxrestore(struct nvhost_job *job)
nvhost_cdma_push_gather(&ch->cdma,
host->nvmap,
nvmap_ref_to_handle(ctx->restore),
+ 0,
nvhost_opcode_gather(ctx->restore_size),
ctx->restore_phys);
@@ -179,12 +182,14 @@ void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
void submit_gathers(struct nvhost_job *job)
{
/* push user gathers */
- int i = 0;
- for ( ; i < job->num_gathers; i++) {
+ int i;
+ for (i = 0 ; i < job->num_gathers; i++) {
u32 op1 = nvhost_opcode_gather(job->gathers[i].words);
u32 op2 = job->gathers[i].mem;
nvhost_cdma_push_gather(&job->ch->cdma,
- job->nvmap, job->unpins[i/2],
+ job->nvmap,
+ nvmap_id_to_handle(job->gathers[i].mem_id),
+ job->gathers[i].offset,
op1, op2);
}
}
@@ -198,6 +203,7 @@ int host1x_channel_submit(struct nvhost_job *job)
u32 syncval;
int err;
void *completed_waiter = NULL, *ctxsave_waiter = NULL;
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
/* Bail out on timed out contexts */
if (job->hwctx && job->hwctx->has_timedout)
@@ -205,8 +211,8 @@ int host1x_channel_submit(struct nvhost_job *job)
/* Turn on the client module and host1x */
nvhost_module_busy(ch->dev);
- if (ch->dev->busy)
- ch->dev->busy(ch->dev);
+ if (drv->busy)
+ drv->busy(ch->dev);
/* before error checks, return current max */
prev_max = job->syncpt_end =
@@ -544,6 +550,7 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
void *ref;
void *ctx_waiter = NULL, *wakeup_waiter = NULL;
struct nvhost_job *job;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
ctx_waiter = nvhost_intr_alloc_waiter();
wakeup_waiter = nvhost_intr_alloc_waiter();
@@ -552,8 +559,8 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
goto done;
}
- if (dev->busy)
- dev->busy(dev);
+ if (drv->busy)
+ drv->busy(dev);
mutex_lock(&ch->submitlock);
hwctx_to_save = ch->cur_ctx;
diff --git a/drivers/video/tegra/host/host1x/host1x_debug.c b/drivers/video/tegra/host/host1x/host1x_debug.c
index 1a1d764bbd63..76483d82528b 100644
--- a/drivers/video/tegra/host/host1x/host1x_debug.c
+++ b/drivers/video/tegra/host/host1x/host1x_debug.c
@@ -25,10 +25,10 @@
#include "dev.h"
#include "debug.h"
+#include "host1x_hardware.h"
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
#include "../../nvmap/nvmap.h"
-
-#include "host1x_hardware.h"
#include "host1x_cdma.h"
#define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
@@ -174,11 +174,6 @@ static void show_channel_gather(struct output *o, u32 addr,
phys_addr_t pin_addr;
int state, count, i;
- if ((u32)nvmap->handle == NVHOST_CDMA_PUSH_GATHER_CTXSAVE) {
- nvhost_debug_output(o, "[context save]\n");
- return;
- }
-
if (!nvmap->handle || !nvmap->client
|| atomic_read(&nvmap->handle->ref) < 1) {
nvhost_debug_output(o, "[already deallocated]\n");
@@ -394,11 +389,11 @@ static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
nvhost_debug_output(o, "\n");
}
-int nvhost_init_t20_debug_support(struct nvhost_master *host)
+int nvhost_init_t20_debug_support(struct nvhost_chip_support *op)
{
- host->op.debug.show_channel_cdma = t20_debug_show_channel_cdma;
- host->op.debug.show_channel_fifo = t20_debug_show_channel_fifo;
- host->op.debug.show_mlocks = t20_debug_show_mlocks;
+ op->debug.show_channel_cdma = t20_debug_show_channel_cdma;
+ op->debug.show_channel_fifo = t20_debug_show_channel_fifo;
+ op->debug.show_mlocks = t20_debug_show_mlocks;
return 0;
}
diff --git a/drivers/video/tegra/host/host1x/host1x_hwctx.h b/drivers/video/tegra/host/host1x/host1x_hwctx.h
index 7587642d0e14..b5046c461d9d 100644
--- a/drivers/video/tegra/host/host1x/host1x_hwctx.h
+++ b/drivers/video/tegra/host/host1x/host1x_hwctx.h
@@ -24,6 +24,7 @@
#define __NVHOST_HOST1X_HWCTX_H
#include <linux/kref.h>
+#include "nvhost_hwctx.h"
struct nvhost_hwctx_handler;
struct nvhost_channel;
diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c
index 47e984e2943e..2b611faaa708 100644
--- a/drivers/video/tegra/host/host1x/host1x_intr.c
+++ b/drivers/video/tegra/host/host1x/host1x_intr.c
@@ -3,6 +3,7 @@
*
* Tegra Graphics Host Interrupt Management
*
+ * Copyright (C) 2010 Google, Inc.
* Copyright (c) 2010-2012, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,18 +21,69 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/mach/irq.h>
#include "nvhost_intr.h"
#include "dev.h"
#include "host1x_hardware.h"
-
/*** HW host sync management ***/
+static void syncpt_thresh_mask(struct irq_data *data)
+{
+ (void)data;
+}
+
+static void syncpt_thresh_unmask(struct irq_data *data)
+{
+ (void)data;
+}
+
+static void syncpt_thresh_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *sync_regs = irq_desc_get_handler_data(desc);
+ unsigned long reg;
+ int id;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
+ reg = readl(sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+
+ for_each_set_bit(id, &reg, 32)
+ generic_handle_irq(id + INT_SYNCPT_THRESH_BASE);
+
+ chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip syncpt_thresh_irq = {
+ .name = "syncpt",
+ .irq_mask = syncpt_thresh_mask,
+ .irq_unmask = syncpt_thresh_unmask
+};
+
static void t20_intr_init_host_sync(struct nvhost_intr *intr)
{
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
+ int i, irq;
+
+ writel(0xffffffffUL,
+ sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
+ writel(0xffffffffUL,
+ sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+
+ for (i = 0; i < INT_SYNCPT_THRESH_NR; i++) {
+ irq = INT_SYNCPT_THRESH_BASE + i;
+ irq_set_chip_and_handler(irq, &syncpt_thresh_irq,
+ handle_simple_irq);
+ irq_set_chip_data(irq, sync_regs);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_chained_handler(INT_HOST1X_MPCORE_SYNCPT,
+ syncpt_thresh_cascade);
+ irq_set_handler_data(INT_HOST1X_MPCORE_SYNCPT, sync_regs);
/* disable the ip_busy_timeout. this prevents write drops, etc.
* there's no real way to recover from a hung client anyway.
*/
@@ -198,21 +250,16 @@ static int t20_request_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
return 0;
}
-int nvhost_init_t20_intr_support(struct nvhost_master *host)
+int nvhost_init_t20_intr_support(struct nvhost_chip_support *op)
{
- host->op.intr.init_host_sync = t20_intr_init_host_sync;
- host->op.intr.set_host_clocks_per_usec =
- t20_intr_set_host_clocks_per_usec;
- host->op.intr.set_syncpt_threshold = t20_intr_set_syncpt_threshold;
- host->op.intr.enable_syncpt_intr = t20_intr_enable_syncpt_intr;
- host->op.intr.disable_all_syncpt_intrs =
- t20_intr_disable_all_syncpt_intrs;
- host->op.intr.request_host_general_irq =
- t20_intr_request_host_general_irq;
- host->op.intr.free_host_general_irq =
- t20_intr_free_host_general_irq;
- host->op.intr.request_syncpt_irq =
- t20_request_syncpt_irq;
+ op->intr.init_host_sync = t20_intr_init_host_sync;
+ op->intr.set_host_clocks_per_usec = t20_intr_set_host_clocks_per_usec;
+ op->intr.set_syncpt_threshold = t20_intr_set_syncpt_threshold;
+ op->intr.enable_syncpt_intr = t20_intr_enable_syncpt_intr;
+ op->intr.disable_all_syncpt_intrs = t20_intr_disable_all_syncpt_intrs;
+ op->intr.request_host_general_irq = t20_intr_request_host_general_irq;
+ op->intr.free_host_general_irq = t20_intr_free_host_general_irq;
+ op->intr.request_syncpt_irq = t20_request_syncpt_irq;
return 0;
}
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.c b/drivers/video/tegra/host/host1x/host1x_syncpt.c
index b431fa350638..b7d6587acc61 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.c
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.c
@@ -19,10 +19,14 @@
*/
#include <linux/nvhost_ioctl.h>
+#include <linux/io.h>
+#include <trace/events/nvhost.h>
#include "nvhost_syncpt.h"
+#include "nvhost_acm.h"
#include "dev.h"
#include "host1x_syncpt.h"
#include "host1x_hardware.h"
+#include "chip_support.h"
/**
* Write the current syncpoint value back to hw.
@@ -122,6 +126,8 @@ static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
u32 override;
BUG_ON(wait->syncpt_id >= NV_HOST1X_SYNCPT_NB_PTS);
+ trace_nvhost_syncpt_wait_check(wait->mem, wait->offset,
+ wait->syncpt_id, wait->thresh);
if (nvhost_syncpt_is_expired(sp,
wait->syncpt_id, wait->thresh)) {
/*
@@ -135,7 +141,7 @@ static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
dev_dbg(&syncpt_to_dev(sp)->dev->dev,
"drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
wait->syncpt_id,
- syncpt_op(sp).name(sp, wait->syncpt_id),
+ syncpt_op().name(sp, wait->syncpt_id),
wait->thresh,
nvhost_syncpt_read_min(sp, wait->syncpt_id));
@@ -189,7 +195,7 @@ static void t20_syncpt_debug(struct nvhost_syncpt *sp)
continue;
dev_info(&syncpt_to_dev(sp)->dev->dev,
"id %d (%s) min %d max %d\n",
- i, syncpt_op(sp).name(sp, i),
+ i, syncpt_op().name(sp, i),
min, max);
}
@@ -223,23 +229,23 @@ static void syncpt_mutex_unlock(struct nvhost_syncpt *sp,
writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
}
-int host1x_init_syncpt_support(struct nvhost_master *host)
+int host1x_init_syncpt_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
-
host->sync_aperture = host->aperture +
(NV_HOST1X_CHANNEL0_BASE +
HOST1X_CHANNEL_SYNC_REG_BASE);
- host->op.syncpt.reset = t20_syncpt_reset;
- host->op.syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
- host->op.syncpt.read_wait_base = t20_syncpt_read_wait_base;
- host->op.syncpt.update_min = t20_syncpt_update_min;
- host->op.syncpt.cpu_incr = t20_syncpt_cpu_incr;
- host->op.syncpt.wait_check = t20_syncpt_wait_check;
- host->op.syncpt.debug = t20_syncpt_debug;
- host->op.syncpt.name = t20_syncpt_name;
- host->op.syncpt.mutex_try_lock = syncpt_mutex_try_lock;
- host->op.syncpt.mutex_unlock = syncpt_mutex_unlock;
+ op->syncpt.reset = t20_syncpt_reset;
+ op->syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
+ op->syncpt.read_wait_base = t20_syncpt_read_wait_base;
+ op->syncpt.update_min = t20_syncpt_update_min;
+ op->syncpt.cpu_incr = t20_syncpt_cpu_incr;
+ op->syncpt.wait_check = t20_syncpt_wait_check;
+ op->syncpt.debug = t20_syncpt_debug;
+ op->syncpt.name = t20_syncpt_name;
+ op->syncpt.mutex_try_lock = syncpt_mutex_try_lock;
+ op->syncpt.mutex_unlock = syncpt_mutex_unlock;
host->syncpt.nb_pts = NV_HOST1X_SYNCPT_NB_PTS;
host->syncpt.nb_bases = NV_HOST1X_SYNCPT_NB_BASES;
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.h b/drivers/video/tegra/host/host1x/host1x_syncpt.h
index 0d263dc92ed5..1e94a2b846eb 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.h
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.h
@@ -71,7 +71,10 @@
#define NVWAITBASE_MPE (4)
struct nvhost_master;
+struct nvhost_chip_support;
+
int host1x_init_syncpt(struct nvhost_master *host);
-int host1x_init_syncpt_support(struct nvhost_master *host);
+int host1x_init_syncpt_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op);
#endif
diff --git a/drivers/video/tegra/host/isp/isp.c b/drivers/video/tegra/host/isp/isp.c
index 9044d40b8574..ae9d7eb09365 100644
--- a/drivers/video/tegra/host/isp/isp.c
+++ b/drivers/video/tegra/host/isp/isp.c
@@ -25,7 +25,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit isp_probe(struct nvhost_device *dev)
+static int __devinit isp_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
index 36d1d6f26682..d8c9da7e9a76 100644
--- a/drivers/video/tegra/host/mpe/mpe.c
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -19,6 +19,7 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
#include "dev.h"
#include "host1x/host1x_hardware.h"
#include "host1x/host1x_channel.h"
@@ -30,6 +31,7 @@
#include <linux/resource.h>
#include <mach/iomap.h>
+#include <mach/hardware.h>
#include "bus_client.h"
@@ -459,6 +461,7 @@ static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
ctx->hwctx.valid = false;
ctx->save_incrs = 3;
ctx->save_thresh = 2;
+ ctx->save_slots = p->save_slots;
ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
ctx->restore_size = restore_size;
ctx->restore_incrs = 1;
@@ -497,7 +500,10 @@ static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
{
struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
- nvhost_cdma_push(cdma,
+ nvhost_cdma_push_gather(cdma,
+ nvhost_get_host(nctx->channel->dev)->nvmap,
+ h->save_buf->handle,
+ 0,
nvhost_opcode_gather(h->save_size),
h->save_phys);
}
@@ -528,9 +534,8 @@ static void ctxmpe_save_service(struct nvhost_hwctx *nctx)
h->syncpt);
}
-struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
- u32 syncpt, u32 waitbase,
- struct nvhost_channel *ch)
+struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch)
{
struct nvmap_client *nvmap;
u32 *save_ptr;
@@ -562,6 +567,7 @@ struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
}
p->save_phys = nvmap_pin(nvmap, p->save_buf);
+ p->save_slots = 1;
setup_save(p, save_ptr);
@@ -579,9 +585,51 @@ int nvhost_mpe_prepare_power_off(struct nvhost_device *dev)
return host1x_save_context(dev, NVSYNCPT_MPE);
}
-static int __devinit mpe_probe(struct nvhost_device *dev)
+enum mpe_ip_ver {
+ mpe_01,
+ mpe_02,
+};
+
+struct mpe_desc {
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
+};
+
+static const struct mpe_desc mpe[] = {
+ [mpe_01] = {
+ .prepare_poweroff = nvhost_mpe_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
+ },
+ [mpe_02] = {
+ .prepare_poweroff = nvhost_mpe_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
+ },
+};
+
+static struct nvhost_device_id mpe_id[] = {
+ { "mpe01", mpe_01 },
+ { "mpe02", mpe_02 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(nvhost, mpe_id);
+
+static int __devinit mpe_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
+ int index = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ index = id_table->driver_data;
+
+ drv->prepare_poweroff = mpe[index].prepare_poweroff;
+ drv->alloc_hwctx_handler = mpe[index].alloc_hwctx_handler;
+
+ /* reset device name so that consistent device name can be
+ * found in clock tree */
+ dev->name = "mpe";
err = nvhost_client_device_get_resources(dev);
if (err)
@@ -626,7 +674,8 @@ static struct nvhost_driver mpe_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "mpe",
- }
+ },
+ .id_table = mpe_id,
};
static int __init mpe_init(void)
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index f2a61a9547a0..6d96bd023d81 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -55,15 +55,8 @@ static void do_unpowergate_locked(int id)
tegra_unpowergate_partition(id);
}
-void nvhost_module_reset(struct nvhost_device *dev)
+static void do_module_reset_locked(struct nvhost_device *dev)
{
- dev_dbg(&dev->dev,
- "%s: asserting %s module reset (id %d, id2 %d)\n",
- __func__, dev->name,
- dev->powergate_ids[0], dev->powergate_ids[1]);
-
- mutex_lock(&dev->lock);
-
/* assert module and mc client reset */
if (dev->powergate_ids[0] != -1) {
tegra_powergate_mc_disable(dev->powergate_ids[0]);
@@ -89,7 +82,17 @@ void nvhost_module_reset(struct nvhost_device *dev)
tegra_periph_reset_deassert(dev->clk[1]);
tegra_powergate_mc_enable(dev->powergate_ids[1]);
}
+}
+void nvhost_module_reset(struct nvhost_device *dev)
+{
+ dev_dbg(&dev->dev,
+ "%s: asserting %s module reset (id %d, id2 %d)\n",
+ __func__, dev->name,
+ dev->powergate_ids[0], dev->powergate_ids[1]);
+
+ mutex_lock(&dev->lock);
+ do_module_reset_locked(dev);
mutex_unlock(&dev->lock);
dev_dbg(&dev->dev, "%s: module %s out of reset\n",
@@ -108,15 +111,21 @@ static void to_state_clockgated_locked(struct nvhost_device *dev)
&& dev->can_powergate) {
do_unpowergate_locked(dev->powergate_ids[0]);
do_unpowergate_locked(dev->powergate_ids[1]);
+
+ if (dev->powerup_reset)
+ do_module_reset_locked(dev);
}
dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED;
}
static void to_state_running_locked(struct nvhost_device *dev)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
int prev_state = dev->powerstate;
+
if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED)
to_state_clockgated_locked(dev);
+
if (dev->powerstate == NVHOST_POWER_STATE_CLOCKGATED) {
int i;
@@ -129,8 +138,8 @@ static void to_state_running_locked(struct nvhost_device *dev)
}
if (prev_state == NVHOST_POWER_STATE_POWERGATED
- && dev->finalize_poweron)
- dev->finalize_poweron(dev);
+ && drv->finalize_poweron)
+ drv->finalize_poweron(dev);
}
dev->powerstate = NVHOST_POWER_STATE_RUNNING;
}
@@ -142,12 +151,13 @@ static void to_state_running_locked(struct nvhost_device *dev)
static int to_state_powergated_locked(struct nvhost_device *dev)
{
int err = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
- if (dev->prepare_poweroff
+ if (drv->prepare_poweroff
&& dev->powerstate != NVHOST_POWER_STATE_POWERGATED) {
/* Clock needs to be on in prepare_poweroff */
to_state_running_locked(dev);
- err = dev->prepare_poweroff(dev);
+ err = drv->prepare_poweroff(dev);
if (err)
return err;
}
@@ -179,8 +189,10 @@ static void schedule_clockgating_locked(struct nvhost_device *dev)
void nvhost_module_busy(struct nvhost_device *dev)
{
- if (dev->busy)
- dev->busy(dev);
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ if (drv->busy)
+ drv->busy(dev);
mutex_lock(&dev->lock);
cancel_delayed_work(&dev->powerstate_down);
@@ -220,6 +232,7 @@ static void powerstate_down_handler(struct work_struct *work)
void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
bool kick = false;
mutex_lock(&dev->lock);
@@ -234,8 +247,8 @@ void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
if (kick) {
wake_up(&dev->idle_wq);
- if (dev->idle)
- dev->idle(dev);
+ if (drv->idle)
+ drv->idle(dev);
}
}
@@ -397,6 +410,7 @@ static int is_module_idle(struct nvhost_device *dev)
int nvhost_module_suspend(struct nvhost_device *dev)
{
int ret;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
ret = wait_event_timeout(dev->idle_wq, is_module_idle(dev),
ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT);
@@ -411,8 +425,8 @@ int nvhost_module_suspend(struct nvhost_device *dev)
to_state_powergated_locked(dev);
mutex_unlock(&dev->lock);
- if (dev->suspend)
- dev->suspend(dev);
+ if (drv->suspend_ndev)
+ drv->suspend_ndev(dev);
return 0;
}
@@ -420,9 +434,10 @@ int nvhost_module_suspend(struct nvhost_device *dev)
void nvhost_module_deinit(struct nvhost_device *dev)
{
int i;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
- if (dev->deinit)
- dev->deinit(dev);
+ if (drv->deinit)
+ drv->deinit(dev);
nvhost_module_suspend(dev);
for (i = 0; i < dev->num_clks; i++)
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
index 775d761e65c9..a72e18f16ac7 100644
--- a/drivers/video/tegra/host/nvhost_cdma.c
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -19,7 +19,11 @@
*/
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
#include "dev.h"
+#include "debug.h"
#include <asm/cacheflush.h>
#include <linux/slab.h>
@@ -65,8 +69,8 @@ static unsigned int cdma_status_locked(struct nvhost_cdma *cdma,
return list_empty(&cdma->sync_queue) ? 1 : 0;
case CDMA_EVENT_PUSH_BUFFER_SPACE: {
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).space);
- return cdma_pb_op(cdma).space(pb);
+ BUG_ON(!cdma_pb_op().space);
+ return cdma_pb_op().space(pb);
}
default:
return 0;
@@ -92,7 +96,13 @@ unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
trace_nvhost_wait_cdma(cdma_to_channel(cdma)->dev->name,
event);
- BUG_ON(cdma->event != CDMA_EVENT_NONE);
+ /* If somebody has managed to already start waiting, yield */
+ if (cdma->event != CDMA_EVENT_NONE) {
+ mutex_unlock(&cdma->lock);
+ schedule();
+ mutex_lock(&cdma->lock);
+ continue;
+ }
cdma->event = event;
mutex_unlock(&cdma->lock);
@@ -153,7 +163,9 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
struct nvhost_syncpt *sp = &dev->syncpt;
struct nvhost_job *job, *n;
- BUG_ON(!cdma->running);
+ /* If CDMA is stopped, queue is cleared and we can return */
+ if (!cdma->running)
+ return;
/*
* Walk the sync queue, reading the sync point registers as necessary,
@@ -181,8 +193,8 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
/* Pop push buffer slots */
if (job->num_slots) {
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).pop_from);
- cdma_pb_op(cdma).pop_from(pb, job->num_slots);
+ BUG_ON(!cdma_pb_op().pop_from);
+ cdma_pb_op().pop_from(pb, job->num_slots);
if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
signal = true;
}
@@ -207,7 +219,6 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
{
u32 get_restart;
u32 syncpt_incrs;
- bool exec_ctxsave;
struct nvhost_job *job = NULL;
u32 syncpt_val;
@@ -274,7 +285,7 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
nvhost_job_dump(dev, job);
/* safe to use CPU to incr syncpts */
- cdma_op(cdma).timeout_cpu_incr(cdma,
+ cdma_op().timeout_cpu_incr(cdma,
job->first_get,
syncpt_incrs,
job->syncpt_end,
@@ -284,45 +295,10 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
}
dev_dbg(dev,
- "%s: GPU incr blocked interleaved ctx buffers\n",
- __func__);
-
- exec_ctxsave = false;
-
- /* setup GPU increments */
- list_for_each_entry_from(job, &cdma->sync_queue, list) {
- /* same context, increment in the pushbuffer */
- if (job->clientid == cdma->timeout.clientid) {
- /* won't need a timeout when replayed */
- job->timeout = 0;
-
- /* update buffer's syncpts in the pushbuffer */
- cdma_op(cdma).timeout_pb_incr(cdma,
- job->first_get,
- job->syncpt_incrs,
- job->num_slots,
- exec_ctxsave);
-
- exec_ctxsave = false;
- } else {
- dev_dbg(dev,
- "%s: switch to a different userctx\n",
- __func__);
- /*
- * If previous context was the timed out context
- * then clear its CTXSAVE in this slot.
- */
- exec_ctxsave = true;
- }
-
- nvhost_job_dump(dev, job);
- }
-
- dev_dbg(dev,
"%s: finished sync_queue modification\n", __func__);
/* roll back DMAGET and start up channel again */
- cdma_op(cdma).timeout_teardown_end(cdma, get_restart);
+ cdma_op().timeout_teardown_end(cdma, get_restart);
if (cdma->timeout.ctx)
cdma->timeout.ctx->has_timedout = true;
@@ -335,7 +311,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
{
int err;
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).init);
+ BUG_ON(!cdma_pb_op().init);
mutex_init(&cdma->lock);
sema_init(&cdma->sem, 0);
@@ -345,7 +321,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
cdma->running = false;
cdma->torndown = false;
- err = cdma_pb_op(cdma).init(pb);
+ err = cdma_pb_op().init(pb);
if (err)
return err;
return 0;
@@ -358,10 +334,10 @@ void nvhost_cdma_deinit(struct nvhost_cdma *cdma)
{
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).destroy);
+ BUG_ON(!cdma_pb_op().destroy);
BUG_ON(cdma->running);
- cdma_pb_op(cdma).destroy(pb);
- cdma_op(cdma).timeout_destroy(cdma);
+ cdma_pb_op().destroy(pb);
+ cdma_op().timeout_destroy(cdma);
}
/**
@@ -375,8 +351,8 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
/* init state on first submit with timeout value */
if (!cdma->timeout.initialized) {
int err;
- BUG_ON(!cdma_op(cdma).timeout_init);
- err = cdma_op(cdma).timeout_init(cdma,
+ BUG_ON(!cdma_op().timeout_init);
+ err = cdma_op().timeout_init(cdma,
job->syncpt_id);
if (err) {
mutex_unlock(&cdma->lock);
@@ -385,22 +361,58 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
}
}
if (!cdma->running) {
- BUG_ON(!cdma_op(cdma).start);
- cdma_op(cdma).start(cdma);
+ BUG_ON(!cdma_op().start);
+ cdma_op().start(cdma);
}
cdma->slots_free = 0;
cdma->slots_used = 0;
- cdma->first_get = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ cdma->first_get = cdma_pb_op().putptr(&cdma->push_buffer);
return 0;
}
+static void trace_write_gather(struct nvhost_cdma *cdma,
+ struct nvmap_handle *handle,
+ u32 offset, u32 words)
+{
+ struct nvmap_handle_ref ref;
+ void *mem = NULL;
+
+ if (nvhost_debug_trace_cmdbuf) {
+ ref.handle = handle;
+ mem = nvmap_mmap(&ref);
+ if (IS_ERR_OR_NULL(mem))
+ mem = NULL;
+ };
+
+ if (mem) {
+ u32 i;
+ /*
+ * Write in batches of 128 as there seems to be a limit
+ * of how much you can output to ftrace at once.
+ */
+ for (i = 0; i < words; i += TRACE_MAX_LENGTH) {
+ trace_nvhost_cdma_push_gather(
+ cdma_to_channel(cdma)->dev->name,
+ (u32)handle,
+ min(words - i, TRACE_MAX_LENGTH),
+ offset + i * sizeof(u32),
+ mem);
+ }
+ nvmap_munmap(&ref, mem);
+ }
+}
+
/**
* Push two words into a push buffer slot
* Blocks as necessary if the push buffer is full.
*/
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
{
- nvhost_cdma_push_gather(cdma, NULL, NULL, op1, op2);
+ if (nvhost_debug_trace_cmdbuf)
+ trace_nvhost_cdma_push(cdma_to_channel(cdma)->dev->name,
+ op1, op2);
+
+ nvhost_cdma_push_gather(cdma, NULL, NULL, 0, op1, op2);
}
/**
@@ -409,20 +421,26 @@ void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
*/
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2)
+ struct nvmap_handle *handle,
+ u32 offset, u32 op1, u32 op2)
{
u32 slots_free = cdma->slots_free;
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).push_to);
- BUG_ON(!cdma_op(cdma).kick);
+
+ BUG_ON(!cdma_pb_op().push_to);
+ BUG_ON(!cdma_op().kick);
+
+ if (handle)
+ trace_write_gather(cdma, handle, offset, op1 & 0xffff);
+
if (slots_free == 0) {
- cdma_op(cdma).kick(cdma);
+ cdma_op().kick(cdma);
slots_free = nvhost_cdma_wait_locked(cdma,
CDMA_EVENT_PUSH_BUFFER_SPACE);
}
cdma->slots_free = slots_free - 1;
cdma->slots_used++;
- cdma_pb_op(cdma).push_to(pb, client, handle, op1, op2);
+ cdma_pb_op().push_to(pb, client, handle, op1, op2);
}
/**
@@ -436,8 +454,8 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
{
bool was_idle = list_empty(&cdma->sync_queue);
- BUG_ON(!cdma_op(cdma).kick);
- cdma_op(cdma).kick(cdma);
+ BUG_ON(!cdma_op().kick);
+ cdma_op().kick(cdma);
BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h
index 9cb9b8277254..e6f51179150f 100644
--- a/drivers/video/tegra/host/nvhost_cdma.h
+++ b/drivers/video/tegra/host/nvhost_cdma.h
@@ -25,11 +25,9 @@
#include <linux/semaphore.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/list.h>
-#include "nvhost_acm.h"
-
struct nvhost_syncpt;
struct nvhost_userctx_timeout;
struct nvhost_job;
@@ -97,7 +95,6 @@ struct nvhost_cdma {
unsigned int first_get; /* DMAGET value, where submit begins */
unsigned int last_put; /* last value written to DMAPUT */
struct push_buffer push_buffer; /* channel's push buffer */
- struct syncpt_buffer syncpt_buffer; /* syncpt incr buffer */
struct list_head sync_queue; /* job queue */
struct buffer_timeout timeout; /* channel's timeout state/wq */
bool running;
@@ -106,20 +103,17 @@ struct nvhost_cdma {
#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
#define cdma_to_dev(cdma) nvhost_get_host(cdma_to_channel(cdma)->dev)
-#define cdma_op(cdma) (cdma_to_dev(cdma)->op.cdma)
#define cdma_to_nvmap(cdma) ((cdma_to_dev(cdma))->nvmap)
#define pb_to_cdma(pb) container_of(pb, struct nvhost_cdma, push_buffer)
-#define cdma_pb_op(cdma) (cdma_to_dev(cdma)->op.push_buffer)
int nvhost_cdma_init(struct nvhost_cdma *cdma);
void nvhost_cdma_deinit(struct nvhost_cdma *cdma);
void nvhost_cdma_stop(struct nvhost_cdma *cdma);
int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job);
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2);
-#define NVHOST_CDMA_PUSH_GATHER_CTXSAVE 0xffffffff
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2);
+ struct nvmap_handle *handle, u32 offset, u32 op1, u32 op2);
void nvhost_cdma_end(struct nvhost_cdma *cdma,
struct nvhost_job *job);
void nvhost_cdma_update(struct nvhost_cdma *cdma);
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
index afbac6fe4c4e..ef8886fe4652 100644
--- a/drivers/video/tegra/host/nvhost_channel.c
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -20,13 +20,14 @@
#include "nvhost_channel.h"
#include "dev.h"
+#include "nvhost_acm.h"
#include "nvhost_job.h"
+#include "chip_support.h"
+
#include <trace/events/nvhost.h>
#include <linux/nvhost_ioctl.h>
#include <linux/slab.h>
-#include <linux/platform_device.h>
-
#define NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT 50
int nvhost_channel_init(struct nvhost_channel *ch,
@@ -36,7 +37,7 @@ int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_device *ndev;
/* Link nvhost_device to nvhost_channel */
- err = host_channel_op(dev).init(ch, dev, index);
+ err = channel_op().init(ch, dev, index);
if (err < 0) {
dev_err(&dev->dev->dev, "failed to init channel %d\n",
index);
@@ -57,16 +58,18 @@ int nvhost_channel_submit(struct nvhost_job *job)
(void)nvhost_cdma_flush(&job->ch->cdma,
NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
- return channel_op(job->ch).submit(job);
+ return channel_op().submit(job);
}
struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
{
int err = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
+
mutex_lock(&ch->reflock);
if (ch->refcount == 0) {
- if (ch->dev->init)
- ch->dev->init(ch->dev);
+ if (drv->init)
+ drv->init(ch->dev);
err = nvhost_cdma_init(&ch->cdma);
} else if (ch->dev->exclusive) {
err = -EBUSY;
@@ -85,7 +88,7 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
{
- BUG_ON(!channel_cdma_op(ch).stop);
+ BUG_ON(!channel_cdma_op().stop);
if (ctx) {
mutex_lock(&ch->submitlock);
@@ -100,7 +103,7 @@ void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
mutex_lock(&ch->reflock);
if (ch->refcount == 1) {
- channel_cdma_op(ch).stop(&ch->cdma);
+ channel_cdma_op().stop(&ch->cdma);
nvhost_cdma_deinit(&ch->cdma);
nvhost_module_suspend(ch->dev);
}
@@ -113,14 +116,40 @@ int nvhost_channel_suspend(struct nvhost_channel *ch)
int ret = 0;
mutex_lock(&ch->reflock);
- BUG_ON(!channel_cdma_op(ch).stop);
+ BUG_ON(!channel_cdma_op().stop);
if (ch->refcount) {
ret = nvhost_module_suspend(ch->dev);
if (!ret)
- channel_cdma_op(ch).stop(&ch->cdma);
+ channel_cdma_op().stop(&ch->cdma);
}
mutex_unlock(&ch->reflock);
return ret;
}
+
+struct nvhost_channel *nvhost_alloc_channel_internal(int chindex,
+ int max_channels, int *current_channel_count)
+{
+ struct nvhost_channel *ch = NULL;
+
+ if ( (chindex > max_channels) ||
+ ( (*current_channel_count + 1) > max_channels) )
+ return NULL;
+ else {
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (ch == NULL)
+ return NULL;
+ else {
+ (*current_channel_count)++;
+ return ch;
+ }
+ }
+}
+
+void nvhost_free_channel_internal(struct nvhost_channel *ch,
+ int *current_channel_count)
+{
+ kfree(ch);
+ (*current_channel_count)--;
+}
diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h
index 7b946c8ee853..eac51731547b 100644
--- a/drivers/video/tegra/host/nvhost_channel.h
+++ b/drivers/video/tegra/host/nvhost_channel.h
@@ -21,22 +21,20 @@
#ifndef __NVHOST_CHANNEL_H
#define __NVHOST_CHANNEL_H
-#include "nvhost_cdma.h"
-#include "nvhost_acm.h"
-#include "nvhost_hwctx.h"
-#include "nvhost_job.h"
-
#include <linux/cdev.h>
#include <linux/io.h>
+#include "nvhost_cdma.h"
-#define NVHOST_MAX_WAIT_CHECKS 256
-#define NVHOST_MAX_GATHERS 512
-#define NVHOST_MAX_HANDLES 1280
-#define NVHOST_MAX_POWERGATE_IDS 2
+#define NVHOST_MAX_WAIT_CHECKS 256
+#define NVHOST_MAX_GATHERS 512
+#define NVHOST_MAX_HANDLES 1280
+#define NVHOST_MAX_POWERGATE_IDS 2
struct nvhost_master;
struct nvhost_waitchk;
struct nvhost_device;
+struct nvhost_channel;
+struct nvhost_hwctx;
struct nvhost_channel_gather {
u32 words;
@@ -60,8 +58,7 @@ struct nvhost_channel {
struct nvhost_cdma cdma;
};
-int nvhost_channel_init(
- struct nvhost_channel *ch,
+int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_master *dev, int index);
int nvhost_channel_submit(struct nvhost_job *job);
@@ -70,17 +67,17 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch);
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx);
int nvhost_channel_suspend(struct nvhost_channel *ch);
-#define channel_cdma_op(ch) (nvhost_get_host(ch->dev)->op.cdma)
-#define channel_op(ch) (nvhost_get_host(ch->dev)->op.channel)
-#define host_channel_op(host) (host->op.channel)
-
int nvhost_channel_drain_read_fifo(void __iomem *chan_regs,
u32 *ptr, unsigned int count, unsigned int *pending);
-int nvhost_channel_read_3d_reg(
- struct nvhost_channel *channel,
+int nvhost_channel_read_3d_reg(struct nvhost_channel *channel,
struct nvhost_hwctx *hwctx,
- u32 offset,
- u32 *value);
+ u32 offset, u32 *value);
+
+struct nvhost_channel *nvhost_alloc_channel_internal(int chindex,
+ int max_channels, int *current_channel_count);
+
+void nvhost_free_channel_internal(struct nvhost_channel *ch,
+ int *current_channel_count);
#endif
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
index 02a3976f01ce..75ed0be1a72c 100644
--- a/drivers/video/tegra/host/nvhost_hwctx.h
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -25,7 +25,7 @@
#include <linux/kref.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
struct nvhost_channel;
struct nvhost_cdma;
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 7c4bdc7bafb6..ba821f694cb4 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -20,14 +20,13 @@
#include "nvhost_intr.h"
#include "dev.h"
+#include "nvhost_acm.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <trace/events/nvhost.h>
-
-
-
-
+#include "nvhost_channel.h"
+#include "nvhost_hwctx.h"
/*** Wait list management ***/
@@ -116,11 +115,11 @@ void reset_threshold_interrupt(struct nvhost_intr *intr,
{
u32 thresh = list_first_entry(head,
struct nvhost_waitlist, list)->thresh;
- BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
- intr_op(intr).enable_syncpt_intr));
+ BUG_ON(!(intr_op().set_syncpt_threshold &&
+ intr_op().enable_syncpt_intr));
- intr_op(intr).set_syncpt_threshold(intr, id, thresh);
- intr_op(intr).enable_syncpt_intr(intr, id);
+ intr_op().set_syncpt_threshold(intr, id, thresh);
+ intr_op().enable_syncpt_intr(intr, id);
}
@@ -264,8 +263,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
BUG_ON(waiter == NULL);
- BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
- intr_op(intr).enable_syncpt_intr));
+ BUG_ON(!(intr_op().set_syncpt_threshold &&
+ intr_op().enable_syncpt_intr));
/* initialize a new waiter */
INIT_LIST_HEAD(&waiter->list);
@@ -288,8 +287,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
spin_unlock(&syncpt->lock);
mutex_lock(&intr->mutex);
- BUG_ON(!(intr_op(intr).request_syncpt_irq));
- err = intr_op(intr).request_syncpt_irq(syncpt);
+ BUG_ON(!(intr_op().request_syncpt_irq));
+ err = intr_op().request_syncpt_irq(syncpt);
mutex_unlock(&intr->mutex);
if (err) {
@@ -304,11 +303,11 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
if (add_waiter_to_queue(waiter, &syncpt->wait_head)) {
/* added at head of list - new threshold value */
- intr_op(intr).set_syncpt_threshold(intr, id, thresh);
+ intr_op().set_syncpt_threshold(intr, id, thresh);
/* added as first waiter - enable interrupt */
if (queue_was_empty)
- intr_op(intr).enable_syncpt_intr(intr, id);
+ intr_op().enable_syncpt_intr(intr, id);
}
spin_unlock(&syncpt->lock);
@@ -347,6 +346,7 @@ int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync)
u32 nb_pts = host->syncpt.nb_pts;
mutex_init(&intr->mutex);
+ intr_op().init_host_sync(intr);
intr->host_general_irq = irq_gen;
intr->host_general_irq_requested = false;
@@ -374,17 +374,17 @@ void nvhost_intr_deinit(struct nvhost_intr *intr)
void nvhost_intr_start(struct nvhost_intr *intr, u32 hz)
{
- BUG_ON(!(intr_op(intr).init_host_sync &&
- intr_op(intr).set_host_clocks_per_usec &&
- intr_op(intr).request_host_general_irq));
+ BUG_ON(!(intr_op().init_host_sync &&
+ intr_op().set_host_clocks_per_usec &&
+ intr_op().request_host_general_irq));
mutex_lock(&intr->mutex);
- intr_op(intr).init_host_sync(intr);
- intr_op(intr).set_host_clocks_per_usec(intr,
+ intr_op().init_host_sync(intr);
+ intr_op().set_host_clocks_per_usec(intr,
(hz + 1000000 - 1)/1000000);
- intr_op(intr).request_host_general_irq(intr);
+ intr_op().request_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
@@ -395,12 +395,12 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
struct nvhost_intr_syncpt *syncpt;
u32 nb_pts = intr_to_dev(intr)->syncpt.nb_pts;
- BUG_ON(!(intr_op(intr).disable_all_syncpt_intrs &&
- intr_op(intr).free_host_general_irq));
+ BUG_ON(!(intr_op().disable_all_syncpt_intrs &&
+ intr_op().free_host_general_irq));
mutex_lock(&intr->mutex);
- intr_op(intr).disable_all_syncpt_intrs(intr);
+ intr_op().disable_all_syncpt_intrs(intr);
for (id = 0, syncpt = intr->syncpt;
id < nb_pts;
@@ -422,7 +422,7 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
free_syncpt_irq(syncpt);
}
- intr_op(intr).free_host_general_irq(intr);
+ intr_op().free_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
index 26ab04ebd4ab..eea9d837998f 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -74,7 +74,6 @@ struct nvhost_intr {
bool host_general_irq_requested;
};
#define intr_to_dev(x) container_of(x, struct nvhost_master, intr)
-#define intr_op(intr) (intr_to_dev(intr)->op.intr)
#define intr_syncpt_to_intr(is) (is->intr)
/**
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
index df7a62d689bc..71f2ab0e751f 100644
--- a/drivers/video/tegra/host/nvhost_job.c
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -22,9 +22,10 @@
#include <linux/kref.h>
#include <linux/err.h>
#include <linux/vmalloc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvhost_channel.h"
#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
#include "dev.h"
/* Magic to use to fill freed handle slots */
@@ -73,7 +74,7 @@ static int alloc_gathers(struct nvhost_job *job,
gather_size(num_cmdbufs),
32, NVMAP_HANDLE_CACHEABLE, 0);
if (IS_ERR_OR_NULL(job->gather_mem)) {
- err = PTR_ERR(job->gather_mem);
+ err = job->gather_mem ? PTR_ERR(job->gather_mem) : -ENOMEM;
job->gather_mem = NULL;
goto error;
}
@@ -82,7 +83,7 @@ static int alloc_gathers(struct nvhost_job *job,
/* Map memory to kernel */
job->gathers = nvmap_mmap(job->gather_mem);
if (IS_ERR_OR_NULL(job->gathers)) {
- err = PTR_ERR(job->gathers);
+ err = job->gathers ? PTR_ERR(job->gathers) : -ENOMEM;
job->gathers = NULL;
goto error;
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 13ad0fc3a3cf..4835d22881b8 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -21,10 +21,11 @@
#include <linux/nvhost_ioctl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <trace/events/nvhost.h>
#include "nvhost_syncpt.h"
+#include "nvhost_acm.h"
#include "dev.h"
-#define MAX_STUCK_CHECK_COUNT 15
#define MAX_SYNCPT_LENGTH 5
/* Name of sysfs node for min and max value */
static const char *min_name = "min";
@@ -36,12 +37,12 @@ static const char *max_name = "max";
void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
{
u32 i;
- BUG_ON(!(syncpt_op(sp).reset && syncpt_op(sp).reset_wait_base));
+ BUG_ON(!(syncpt_op().reset && syncpt_op().reset_wait_base));
for (i = 0; i < sp->nb_pts; i++)
- syncpt_op(sp).reset(sp, i);
+ syncpt_op().reset(sp, i);
for (i = 0; i < sp->nb_bases; i++)
- syncpt_op(sp).reset_wait_base(sp, i);
+ syncpt_op().reset_wait_base(sp, i);
wmb();
}
@@ -51,17 +52,17 @@ void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
void nvhost_syncpt_save(struct nvhost_syncpt *sp)
{
u32 i;
- BUG_ON(!(syncpt_op(sp).update_min && syncpt_op(sp).read_wait_base));
+ BUG_ON(!(syncpt_op().update_min && syncpt_op().read_wait_base));
for (i = 0; i < sp->nb_pts; i++) {
if (client_managed(i))
- syncpt_op(sp).update_min(sp, i);
+ syncpt_op().update_min(sp, i);
else
BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
}
for (i = 0; i < sp->nb_bases; i++)
- syncpt_op(sp).read_wait_base(sp, i);
+ syncpt_op().read_wait_base(sp, i);
}
/**
@@ -69,9 +70,14 @@ void nvhost_syncpt_save(struct nvhost_syncpt *sp)
*/
u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(!syncpt_op(sp).update_min);
+ u32 val;
+
+ BUG_ON(!syncpt_op().update_min);
- return syncpt_op(sp).update_min(sp, id);
+ return syncpt_op().update_min(sp, id);
+ trace_nvhost_syncpt_update_min(id, val);
+
+ return val;
}
/**
@@ -80,9 +86,9 @@ u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
{
u32 val;
- BUG_ON(!syncpt_op(sp).update_min);
+ BUG_ON(!syncpt_op().update_min);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
- val = syncpt_op(sp).update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
nvhost_module_idle(syncpt_to_dev(sp)->dev);
return val;
}
@@ -93,9 +99,9 @@ u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
{
u32 val;
- BUG_ON(!syncpt_op(sp).read_wait_base);
+ BUG_ON(!syncpt_op().read_wait_base);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
- syncpt_op(sp).read_wait_base(sp, id);
+ syncpt_op().read_wait_base(sp, id);
val = sp->base_val[id];
nvhost_module_idle(syncpt_to_dev(sp)->dev);
return val;
@@ -107,8 +113,8 @@ u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
*/
void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(!syncpt_op(sp).cpu_incr);
- syncpt_op(sp).cpu_incr(sp, id);
+ BUG_ON(!syncpt_op().cpu_incr);
+ syncpt_op().cpu_incr(sp, id);
}
/**
@@ -149,7 +155,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
nvhost_module_busy(syncpt_to_dev(sp)->dev);
/* try to read from register */
- val = syncpt_op(sp).update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
if (nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = val;
@@ -198,20 +204,19 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
}
if (timeout != NVHOST_NO_TIMEOUT)
timeout -= check;
- if (timeout) {
+ if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
dev_warn(&syncpt_to_dev(sp)->dev->dev,
"%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n",
- current->comm, id, syncpt_op(sp).name(sp, id),
+ current->comm, id, syncpt_op().name(sp, id),
thresh, timeout);
- syncpt_op(sp).debug(sp);
- if (check_count > MAX_STUCK_CHECK_COUNT) {
+ syncpt_op().debug(sp);
+ if (check_count == MAX_STUCK_CHECK_COUNT) {
if (low_timeout) {
dev_warn(&syncpt_to_dev(sp)->dev->dev,
"is timeout %d too low?\n",
low_timeout);
}
nvhost_debug_dump(syncpt_to_dev(sp));
- BUG();
}
check_count++;
}
@@ -287,7 +292,7 @@ bool nvhost_syncpt_is_expired(
void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
{
- syncpt_op(sp).debug(sp);
+ syncpt_op().debug(sp);
}
int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
@@ -296,7 +301,7 @@ int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
u32 reg;
nvhost_module_busy(host->dev);
- reg = syncpt_op(sp).mutex_try_lock(sp, idx);
+ reg = syncpt_op().mutex_try_lock(sp, idx);
if (reg) {
nvhost_module_idle(host->dev);
return -EBUSY;
@@ -307,7 +312,7 @@ int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
{
- syncpt_op(sp).mutex_unlock(sp, idx);
+ syncpt_op().mutex_unlock(sp, idx);
nvhost_module_idle(syncpt_to_dev(sp)->dev);
atomic_dec(&sp->lock_counts[idx]);
}
@@ -319,7 +324,7 @@ int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
struct nvhost_waitchk *wait,
int num_waitchk)
{
- return syncpt_op(sp).wait_check(sp, nvmap,
+ return syncpt_op().wait_check(sp, nvmap,
waitchk_mask, wait, num_waitchk);
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
index b71cb3e6287e..b770ed91c76c 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.h
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -24,12 +24,9 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/atomic.h>
-struct nvhost_syncpt;
-struct nvhost_waitchk;
-
/* host managed and invalid syncpt id */
#define NVSYNCPT_GRAPHICS_HOST (0)
#define NVSYNCPT_INVALID (-1)
@@ -59,9 +56,8 @@ void nvhost_syncpt_deinit(struct nvhost_syncpt *);
#define client_managed(id) (BIT(id) & sp->client_managed)
#define syncpt_to_dev(sp) container_of(sp, struct nvhost_master, syncpt)
-#define syncpt_op(sp) (syncpt_to_dev(sp)->op.syncpt)
-#define SYNCPT_CHECK_PERIOD (2*HZ)
-
+#define SYNCPT_CHECK_PERIOD (2 * HZ)
+#define MAX_STUCK_CHECK_COUNT 15
/**
* Updates the value sent to hardware.
@@ -151,6 +147,7 @@ static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thres
* @param: wait - start of filled in array of waitchk structs
* @param: waitend - end ptr (one beyond last valid waitchk)
*/
+struct nvhost_waitchk;
int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
struct nvmap_client *nvmap,
u32 mask,
diff --git a/drivers/video/tegra/host/t20/t20.c b/drivers/video/tegra/host/t20/t20.c
index 24ddedc842e4..f6713d866f19 100644
--- a/drivers/video/tegra/host/t20/t20.c
+++ b/drivers/video/tegra/host/t20/t20.c
@@ -19,17 +19,19 @@
*/
#include <linux/slab.h>
+#include <linux/nvhost_ioctl.h>
#include <mach/powergate.h>
#include "dev.h"
#include "t20.h"
-#include "host1x/host1x_channel.h"
#include "host1x/host1x_syncpt.h"
#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_cdma.h"
#include "gr3d/gr3d.h"
#include "gr3d/gr3d_t20.h"
#include "mpe/mpe.h"
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
+#include "host1x/host1x_channel.h"
+#include "host1x/host1x_cdma.h"
#define NVMODMUTEX_2D_FULL (1)
#define NVMODMUTEX_2D_SIMPLE (2)
@@ -41,7 +43,9 @@
#define NVMODMUTEX_VI (8)
#define NVMODMUTEX_DSI (9)
-#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+#define T20_NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+
+static int t20_num_alloc_channels = 0;
struct nvhost_device t20_devices[] = {
{
@@ -60,15 +64,13 @@ struct nvhost_device t20_devices[] = {
},
{
/* channel 1 */
- .name = "gr3d",
+ .name = "gr3d01",
.id = -1,
.index = 1,
.syncpts = BIT(NVSYNCPT_3D),
.waitbases = BIT(NVWAITBASE_3D),
.modulemutexes = BIT(NVMODMUTEX_3D),
.class = NV_GRAPHICS_3D_CLASS_ID,
- .prepare_poweroff = nvhost_gr3d_prepare_power_off,
- .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
.clocks = {{"gr3d", UINT_MAX}, {"emc", UINT_MAX}, {} },
.powergate_ids = {TEGRA_POWERGATE_3D, -1},
NVHOST_DEFAULT_CLOCKGATE_DELAY,
@@ -117,7 +119,7 @@ struct nvhost_device t20_devices[] = {
},
{
/* channel 5 */
- .name = "mpe",
+ .name = "mpe01",
.id = -1,
.index = 5,
.syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
@@ -126,8 +128,6 @@ struct nvhost_device t20_devices[] = {
.class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
.waitbasesync = true,
.keepalive = true,
- .prepare_poweroff = nvhost_mpe_prepare_power_off,
- .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
.clocks = { {"mpe", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = {TEGRA_POWERGATE_MPE, -1},
@@ -161,9 +161,10 @@ static inline int t20_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
unsigned long waitbases = ch->dev->waitbases;
u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
- if (ch->dev->alloc_hwctx_handler) {
- ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
+ if (drv->alloc_hwctx_handler) {
+ ch->ctxhandler = drv->alloc_hwctx_handler(syncpt,
waitbase, ch);
if (!ch->ctxhandler)
err = -ENOMEM;
@@ -184,50 +185,64 @@ static int t20_channel_init(struct nvhost_channel *ch,
return t20_nvhost_hwctx_handler_init(ch);
}
-int nvhost_init_t20_channel_support(struct nvhost_master *host)
+int nvhost_init_t20_channel_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
- host->nb_channels = NVHOST_NUMCHANNELS;
-
- host->op.channel.init = t20_channel_init;
- host->op.channel.submit = host1x_channel_submit;
- host->op.channel.read3dreg = host1x_channel_read_3d_reg;
+ op->channel.init = t20_channel_init;
+ op->channel.submit = host1x_channel_submit;
+ op->channel.read3dreg = host1x_channel_read_3d_reg;
return 0;
}
-struct nvhost_device *t20_get_nvhost_device(struct nvhost_master *host,
- char *name)
+static void t20_free_nvhost_channel(struct nvhost_channel *ch)
+{
+ nvhost_free_channel_internal(ch, &t20_num_alloc_channels);
+}
+
+static struct nvhost_channel *t20_alloc_nvhost_channel(int chindex)
+{
+ return nvhost_alloc_channel_internal(chindex,
+ T20_NVHOST_NUMCHANNELS, &t20_num_alloc_channels);
+}
+
+struct nvhost_device *t20_get_nvhost_device(char *name)
{
int i;
- for (i = 0; i < host->nb_channels; i++) {
- if (strcmp(t20_devices[i].name, name) == 0)
+ for (i = 0; i < ARRAY_SIZE(t20_devices); i++) {
+ if (strncmp(t20_devices[i].name, name, strlen(name)) == 0)
return &t20_devices[i];
}
return NULL;
}
-int nvhost_init_t20_support(struct nvhost_master *host)
+int nvhost_init_t20_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
int err;
/* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t20_channel_support(host);
+ err = nvhost_init_t20_channel_support(host, op);
if (err)
return err;
- err = host1x_init_cdma_support(host);
+ err = host1x_init_cdma_support(op);
if (err)
return err;
- err = nvhost_init_t20_debug_support(host);
+ err = nvhost_init_t20_debug_support(op);
if (err)
return err;
- err = host1x_init_syncpt_support(host);
+ err = host1x_init_syncpt_support(host, op);
if (err)
return err;
- err = nvhost_init_t20_intr_support(host);
+ err = nvhost_init_t20_intr_support(op);
if (err)
return err;
- host->op.nvhost_dev.get_nvhost_device = t20_get_nvhost_device;
+
+ op->nvhost_dev.get_nvhost_device = t20_get_nvhost_device;
+ op->nvhost_dev.alloc_nvhost_channel = t20_alloc_nvhost_channel;
+ op->nvhost_dev.free_nvhost_channel = t20_free_nvhost_channel;
+
return 0;
}
diff --git a/drivers/video/tegra/host/t20/t20.h b/drivers/video/tegra/host/t20/t20.h
index 93555a55b589..456d3ae1bc03 100644
--- a/drivers/video/tegra/host/t20/t20.h
+++ b/drivers/video/tegra/host/t20/t20.h
@@ -22,12 +22,15 @@
struct nvhost_master;
struct nvhost_module;
+struct nvhost_chip_support;
-int nvhost_init_t20_channel_support(struct nvhost_master *);
-int nvhost_init_t20_debug_support(struct nvhost_master *);
+int nvhost_init_t20_channel_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
+int nvhost_init_t20_debug_support(struct nvhost_chip_support *);
int nvhost_init_t20_syncpt_support(struct nvhost_master *);
-int nvhost_init_t20_intr_support(struct nvhost_master *);
-int nvhost_init_t20_support(struct nvhost_master *host);
+int nvhost_init_t20_intr_support(struct nvhost_chip_support *);
+int nvhost_init_t20_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
int nvhost_t20_save_context(struct nvhost_module *mod, u32 syncpt_id);
#endif /* _NVHOST_T20_H_ */
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
index 8a8b1f4d9240..257ba0849277 100644
--- a/drivers/video/tegra/host/t30/t30.c
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -19,19 +19,21 @@
*/
#include <linux/mutex.h>
+#include <linux/nvhost_ioctl.h>
#include <mach/powergate.h>
#include <mach/iomap.h>
#include "dev.h"
#include "t20/t20.h"
#include "t30.h"
#include "gr3d/gr3d.h"
-#include "mpe/mpe.h"
#include "gr3d/gr3d_t30.h"
#include "gr3d/scale3d.h"
+#include "mpe/mpe.h"
#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_cdma.h"
#include "host1x/host1x_syncpt.h"
#include "chip_support.h"
+#include "nvhost_channel.h"
+#include "host1x/host1x_cdma.h"
#define NVMODMUTEX_2D_FULL (1)
#define NVMODMUTEX_2D_SIMPLE (2)
@@ -45,6 +47,10 @@
#define NVHOST_CHANNEL_BASE 0
+#define T30_NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+
+static int t30_num_alloc_channels = 0;
+
struct nvhost_device t30_devices[] = {
{
/* channel 0 */
@@ -62,27 +68,21 @@ struct nvhost_device t30_devices[] = {
},
{
/* channel 1 */
- .name = "gr3d",
+ .name = "gr3d02",
.id = -1,
.index = 1,
.syncpts = BIT(NVSYNCPT_3D),
.waitbases = BIT(NVWAITBASE_3D),
.modulemutexes = BIT(NVMODMUTEX_3D),
.class = NV_GRAPHICS_3D_CLASS_ID,
- .prepare_poweroff = nvhost_gr3d_prepare_power_off,
- .busy = nvhost_scale3d_notify_busy,
- .idle = nvhost_scale3d_notify_idle,
- .init = nvhost_scale3d_init,
- .deinit = nvhost_scale3d_deinit,
- .suspend = nvhost_scale3d_suspend,
- .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
.clocks = { {"gr3d", UINT_MAX},
{"gr3d2", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = { TEGRA_POWERGATE_3D,
TEGRA_POWERGATE_3D1 },
NVHOST_DEFAULT_CLOCKGATE_DELAY,
- .can_powergate = false,
+ .can_powergate = true,
+ .powerup_reset = true,
.powergate_delay = 250,
.moduleid = NVHOST_MODULE_NONE,
},
@@ -95,7 +95,7 @@ struct nvhost_device t30_devices[] = {
.waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
.modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
- .clocks = { {"gr2d", 0},
+ .clocks = { {"gr2d", UINT_MAX},
{"epp", 0},
{"emc", 300000000} },
NVHOST_MODULE_NO_POWERGATE_IDS,
@@ -129,7 +129,7 @@ struct nvhost_device t30_devices[] = {
},
{
/* channel 5 */
- .name = "mpe",
+ .name = "mpe02",
.id = -1,
.index = 5,
.syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
@@ -138,8 +138,6 @@ struct nvhost_device t30_devices[] = {
.class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
.waitbasesync = true,
.keepalive = true,
- .prepare_poweroff = nvhost_mpe_prepare_power_off,
- .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
.clocks = { {"mpe", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = {TEGRA_POWERGATE_MPE, -1},
@@ -167,9 +165,10 @@ static inline int t30_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
unsigned long waitbases = ch->dev->waitbases;
u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
- if (ch->dev->alloc_hwctx_handler) {
- ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
+ if (drv->alloc_hwctx_handler) {
+ ch->ctxhandler = drv->alloc_hwctx_handler(syncpt,
waitbase, ch);
if (!ch->ctxhandler)
err = -ENOMEM;
@@ -198,54 +197,71 @@ static int t30_channel_init(struct nvhost_channel *ch,
return t30_nvhost_hwctx_handler_init(ch);
}
-int nvhost_init_t30_channel_support(struct nvhost_master *host)
+int nvhost_init_t30_channel_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
- int result = nvhost_init_t20_channel_support(host);
- host->op.channel.init = t30_channel_init;
+ int result = nvhost_init_t20_channel_support(host, op);
+ op->channel.init = t30_channel_init;
return result;
}
-int nvhost_init_t30_debug_support(struct nvhost_master *host)
+
+int nvhost_init_t30_debug_support(struct nvhost_chip_support *op)
{
- nvhost_init_t20_debug_support(host);
- host->op.debug.debug_init = nvhost_scale3d_debug_init;
+ nvhost_init_t20_debug_support(op);
+ op->debug.debug_init = nvhost_scale3d_debug_init;
return 0;
}
-struct nvhost_device *t30_get_nvhost_device(struct nvhost_master *host,
- char *name)
+static void t30_free_nvhost_channel(struct nvhost_channel *ch)
+{
+ nvhost_free_channel_internal(ch, &t30_num_alloc_channels);
+}
+
+static struct nvhost_channel *t30_alloc_nvhost_channel(int chindex)
+{
+ return nvhost_alloc_channel_internal(chindex,
+ T30_NVHOST_NUMCHANNELS, &t30_num_alloc_channels);
+}
+
+struct nvhost_device *t30_get_nvhost_device(char *name)
{
int i;
- for (i = 0; i < host->nb_channels; i++) {
- if (strcmp(t30_devices[i].name, name) == 0)
+ for (i = 0; i < ARRAY_SIZE(t30_devices); i++) {
+ if (strncmp(t30_devices[i].name, name, strlen(name)) == 0)
return &t30_devices[i];
}
return NULL;
}
-int nvhost_init_t30_support(struct nvhost_master *host)
+int nvhost_init_t30_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
int err;
/* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t30_channel_support(host);
+ err = nvhost_init_t30_channel_support(host, op);
if (err)
return err;
- err = host1x_init_cdma_support(host);
+ err = host1x_init_cdma_support(op);
if (err)
return err;
- err = nvhost_init_t30_debug_support(host);
+ err = nvhost_init_t30_debug_support(op);
if (err)
return err;
- err = host1x_init_syncpt_support(host);
+ err = host1x_init_syncpt_support(host, op);
if (err)
return err;
- err = nvhost_init_t20_intr_support(host);
+ err = nvhost_init_t20_intr_support(op);
if (err)
return err;
- host->op.nvhost_dev.get_nvhost_device = t30_get_nvhost_device;
+
+ op->nvhost_dev.get_nvhost_device = t30_get_nvhost_device;
+ op->nvhost_dev.alloc_nvhost_channel = t30_alloc_nvhost_channel;
+ op->nvhost_dev.free_nvhost_channel = t30_free_nvhost_channel;
+
return 0;
}
diff --git a/drivers/video/tegra/host/t30/t30.h b/drivers/video/tegra/host/t30/t30.h
index 0446dbd19b39..e4db97b5613d 100644
--- a/drivers/video/tegra/host/t30/t30.h
+++ b/drivers/video/tegra/host/t30/t30.h
@@ -21,9 +21,12 @@
#define _NVHOST_T30_H_
struct nvhost_master;
+struct nvhost_chip_support;
-int nvhost_init_t30_channel_support(struct nvhost_master *);
-int nvhost_init_t30_debug_support(struct nvhost_master *);
-int nvhost_init_t30_support(struct nvhost_master *host);
+int nvhost_init_t30_channel_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
+int nvhost_init_t30_debug_support(struct nvhost_chip_support *);
+int nvhost_init_t30_support(struct nvhost_master *host,
+ struct nvhost_chip_support *);
#endif /* _NVHOST_T30_H_ */
diff --git a/drivers/video/tegra/host/vi/vi.c b/drivers/video/tegra/host/vi/vi.c
index a6f902a1ac7b..3cfc7e32cbc1 100644
--- a/drivers/video/tegra/host/vi/vi.c
+++ b/drivers/video/tegra/host/vi/vi.c
@@ -25,7 +25,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit vi_probe(struct nvhost_device *dev)
+static int __devinit vi_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index b4b6241618db..a0c4156668e5 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -32,7 +32,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_mru.h"
diff --git a/drivers/video/tegra/nvmap/nvmap.h b/drivers/video/tegra/nvmap/nvmap.h
index 44a0d86b6039..b0fb70f64a5c 100644
--- a/drivers/video/tegra/nvmap/nvmap.h
+++ b/drivers/video/tegra/nvmap/nvmap.h
@@ -30,7 +30,7 @@
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/atomic.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap_heap.h"
struct nvmap_device;
@@ -86,7 +86,7 @@ struct nvmap_handle {
struct mutex lock;
};
-#define NVMAP_DEFAULT_PAGE_POOL_SIZE 8192
+#ifdef CONFIG_NVMAP_PAGE_POOLS
#define NVMAP_UC_POOL NVMAP_HANDLE_UNCACHEABLE
#define NVMAP_WC_POOL NVMAP_HANDLE_WRITE_COMBINE
#define NVMAP_IWB_POOL NVMAP_HANDLE_INNER_CACHEABLE
@@ -103,11 +103,13 @@ struct nvmap_page_pool {
};
int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags);
+#endif
struct nvmap_share {
struct tegra_iovmm_client *iovmm;
wait_queue_head_t pin_wait;
struct mutex pin_lock;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
union {
struct nvmap_page_pool pools[NVMAP_NUM_POOLS];
struct {
@@ -117,6 +119,7 @@ struct nvmap_share {
struct nvmap_page_pool wb_pool;
};
};
+#endif
#ifdef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
struct mutex mru_lock;
struct list_head *mru_lists;
@@ -201,9 +204,6 @@ struct nvmap_handle *nvmap_get_handle_id(struct nvmap_client *client,
struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
size_t size);
-struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
- unsigned long id);
-
int nvmap_alloc_handle_id(struct nvmap_client *client,
unsigned long id, unsigned int heap_mask,
size_t align, unsigned int flags);
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index f84f38c93aad..c78818711f74 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -39,7 +39,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_ioctl.h"
@@ -1182,8 +1182,10 @@ static int nvmap_probe(struct platform_device *pdev)
init_waitqueue_head(&dev->iovmm_master.pin_wait);
mutex_init(&dev->iovmm_master.pin_lock);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
for (i = 0; i < NVMAP_NUM_POOLS; i++)
nvmap_page_pool_init(&dev->iovmm_master.pools[i], i);
+#endif
dev->iovmm_master.iovmm =
tegra_iovmm_alloc_client(dev_name(&pdev->dev), NULL,
@@ -1311,6 +1313,7 @@ static int nvmap_probe(struct platform_device *pdev)
dev, &debug_iovmm_clients_fops);
debugfs_create_file("allocations", 0664, iovmm_root,
dev, &debug_iovmm_allocations_fops);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
for (i = 0; i < NVMAP_NUM_POOLS; i++) {
char name[40];
char *memtype_string[] = {"uc", "wc",
@@ -1321,6 +1324,7 @@ static int nvmap_probe(struct platform_device *pdev)
iovmm_root,
&dev->iovmm_master.pools[i].npages);
}
+#endif
}
}
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 539b7ce9801f..2f24ba515862 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -36,7 +36,7 @@
#include <asm/pgtable.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/vmstat.h>
#include <linux/swap.h>
@@ -66,6 +66,9 @@
* preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN,
* the array is allocated using vmalloc. */
#define PAGELIST_VMALLOC_MIN (PAGE_SIZE * 2)
+
+#ifdef CONFIG_NVMAP_PAGE_POOLS
+
#define NVMAP_TEST_PAGE_POOL_SHRINKER 1
static bool enable_pp = 1;
static int pool_size[NVMAP_NUM_POOLS];
@@ -377,6 +380,7 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
int i;
static int reg = 1;
struct sysinfo info;
+ int highmem_pages = 0;
typedef int (*set_pages_array) (struct page **pages, int addrinarray);
set_pages_array s_cpa[] = {
set_pages_array_uc,
@@ -395,14 +399,16 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
return 0;
si_meminfo(&info);
- if (!pool_size[flags]) {
+ if (!pool_size[flags] && !CONFIG_NVMAP_PAGE_POOL_SIZE)
/* Use 3/8th of total ram for page pools.
* 1/8th for uc, 1/8th for wc and 1/8th for iwb.
*/
pool->max_pages = info.totalram >> 3;
- }
+ else
+ pool->max_pages = CONFIG_NVMAP_PAGE_POOL_SIZE;
+
if (pool->max_pages <= 0 || pool->max_pages >= info.totalram)
- pool->max_pages = NVMAP_DEFAULT_PAGE_POOL_SIZE;
+ goto fail;
pool_size[flags] = pool->max_pages;
pr_info("nvmap %s page pool size=%d pages",
s_memtype_str[flags], pool->max_pages);
@@ -425,7 +431,14 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
__free_page(page);
goto do_cpa;
}
+ if (PageHighMem(page))
+ highmem_pages++;
}
+ si_meminfo(&info);
+ pr_info("nvmap pool = %s, highmem=%d, pool_size=%d,"
+ "totalram=%lu, freeram=%lu, totalhigh=%lu, freehigh=%lu",
+ s_memtype_str[flags], highmem_pages, pool->max_pages,
+ info.totalram, info.freeram, info.totalhigh, info.freehigh);
do_cpa:
(*s_cpa[flags])(pool->page_array, pool->npages);
nvmap_page_pool_unlock(pool);
@@ -436,6 +449,7 @@ fail:
vfree(pool->page_array);
return -ENOMEM;
}
+#endif
static inline void *altalloc(size_t len)
{
@@ -460,7 +474,9 @@ void _nvmap_handle_free(struct nvmap_handle *h)
{
struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int i, nr_page, page_index = 0;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
+#endif
if (nvmap_handle_remove(h->dev, h) != 0)
return;
@@ -481,6 +497,7 @@ void _nvmap_handle_free(struct nvmap_handle *h)
nvmap_mru_remove(share, h);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
if (h->flags < NVMAP_NUM_POOLS)
pool = &share->pools[h->flags];
@@ -490,6 +507,7 @@ void _nvmap_handle_free(struct nvmap_handle *h)
break;
page_index++;
}
+#endif
if (page_index == nr_page)
goto skip_attr_restore;
@@ -538,12 +556,14 @@ static int handle_page_alloc(struct nvmap_client *client,
struct nvmap_handle *h, bool contiguous)
{
size_t size = PAGE_ALIGN(h->size);
- struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int nr_page = size >> PAGE_SHIFT;
pgprot_t prot;
unsigned int i = 0, page_index = 0;
struct page **pages;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
+ struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
+#endif
pages = altalloc(nr_page * sizeof(*pages));
if (!pages)
@@ -562,6 +582,7 @@ static int handle_page_alloc(struct nvmap_client *client,
pages[i] = nth_page(page, i);
} else {
+#ifdef CONFIG_NVMAP_PAGE_POOLS
if (h->flags < NVMAP_NUM_POOLS)
pool = &share->pools[h->flags];
@@ -572,7 +593,7 @@ static int handle_page_alloc(struct nvmap_client *client,
break;
page_index++;
}
-
+#endif
for (; i < nr_page; i++) {
pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP,
PAGE_SIZE);
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.c b/drivers/video/tegra/nvmap/nvmap_heap.c
index 7474f31534ff..a6fe78c42f87 100644
--- a/drivers/video/tegra/nvmap/nvmap_heap.c
+++ b/drivers/video/tegra/nvmap/nvmap_heap.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include <linux/err.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_heap.h"
#include "nvmap_common.h"
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
index 58bc71d50469..14787154523f 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.c
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -31,7 +31,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap_ioctl.h"
#include "nvmap.h"
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.h b/drivers/video/tegra/nvmap/nvmap_ioctl.h
index 54627683ccdb..300ce9b9a6ea 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.h
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.h
@@ -27,7 +27,7 @@
#ifdef __KERNEL__
#include <linux/file.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#endif
enum {
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index a3ef66a2a083..be18556b84d0 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -26,6 +26,12 @@ extern unsigned long __sw_hweight64(__u64 w);
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
+/* same as for_each_set_bit() but use bit as value to start with */
+#define for_each_set_bit_from(bit, addr, size) \
+ for ((bit) = find_next_bit((addr), (size), (bit)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
static __inline__ int get_bitmask_order(unsigned int count)
{
int order;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42ac294..59b428e5fbc5 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -41,6 +41,26 @@ struct clk;
struct clk *clk_get(struct device *dev, const char *id);
/**
+ * devm_clk_get - lookup and obtain a managed reference to a clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock comsumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno. The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer. (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * devm_clk_get should not be called from within interrupt context.
+ *
+ * The clock will automatically be freed when the device is unbound
+ * from the bus.
+ */
+struct clk *devm_clk_get(struct device *dev, const char *id);
+
+/**
* clk_enable - inform the system when the clock source should be running.
* @clk: clock source
*
@@ -83,6 +103,18 @@ unsigned long clk_get_rate(struct clk *clk);
*/
void clk_put(struct clk *clk);
+/**
+ * devm_clk_put - "free" a managed clock source
+ * @dev: device used to acuqire the clock
+ * @clk: clock source acquired with devm_clk_get()
+ *
+ * Note: drivers must ensure that all clk_enable calls made on this
+ * clock source are balanced by clk_disable calls prior to calling
+ * this function.
+ *
+ * clk_put should not be called from within interrupt context.
+ */
+void devm_clk_put(struct device *dev, struct clk *clk);
/*
* The remaining APIs are optional for machine class support.
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index c6126b9fb7cf..09b8ea9e194b 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -310,6 +310,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
*********************************************************************/
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu);
+int cpufreq_set_gov(char *target_gov, unsigned int cpu);
#ifdef CONFIG_CPU_FREQ
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
diff --git a/include/linux/device.h b/include/linux/device.h
index 28c35f876b19..62608d13da3c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -913,4 +913,25 @@ extern long sysfs_deprecated;
#define sysfs_deprecated 0
#endif
+/**
+ * module_driver() - Helper macro for drivers that don't do anything
+ * special in module init/exit. This eliminates a lot of boilerplate.
+ * Each module may only use this macro once, and calling it replaces
+ * module_init() and module_exit().
+ *
+ * Use this macro to construct bus specific macros for registering
+ * drivers, and do not use it on its own.
+ */
+#define module_driver(__driver, __register, __unregister) \
+static int __init __driver##_init(void) \
+{ \
+ return __register(&(__driver)); \
+} \
+module_init(__driver##_init); \
+static void __exit __driver##_exit(void) \
+{ \
+ __unregister(&(__driver)); \
+} \
+module_exit(__driver##_exit);
+
#endif /* _DEVICE_H_ */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 0bd9ea2b62ea..8d3eab3226ad 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -468,6 +468,19 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
{
return adap->nr;
}
+
+/**
+ * module_i2c_driver() - Helper macro for registering a I2C driver
+ * @__i2c_driver: i2c_driver struct
+ *
+ * Helper macro for I2C drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_i2c_driver(__i2c_driver) \
+ module_driver(__i2c_driver, i2c_add_driver, \
+ i2c_del_driver)
+
#endif /* I2C */
#endif /* __KERNEL__ */
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index bb92f0b13288..4fea7107fee8 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -862,22 +862,6 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
#define TWL6030_REG_VDAC 45
#define TWL6030_REG_VUSB 46
-/* These are renamed in 6025 but same registers */
-#define TWL6025_REG_LDO2 48
-#define TWL6025_REG_LDO4 49
-#define TWL6025_REG_LDO3 50
-#define TWL6025_REG_LDO5 51
-#define TWL6025_REG_LDO1 52
-#define TWL6025_REG_LDO7 53
-#define TWL6025_REG_LDO6 54
-#define TWL6025_REG_LDOLN 55
-#define TWL6025_REG_LDOUSB 56
-
-/* 6025 DCDC supplies */
-#define TWL6025_REG_SMPS3 57
-#define TWL6025_REG_SMPS4 58
-#define TWL6025_REG_VIO 59
-
/* INTERNAL LDOs */
#define TWL6030_REG_VRTC 47
#define TWL6030_REG_CLK32KG 48
diff --git a/include/linux/interrupt_keys.h b/include/linux/interrupt_keys.h
deleted file mode 100755
index 8be6e9a6b0a0..000000000000
--- a/include/linux/interrupt_keys.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * include/linux/interrupt_keys.h
- *
- * Key driver for keys directly connected to intrrupt lines.
- *
- * Copyright (c) 2011, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef _INTERRUPT_KEYS_H
-#define _INTERRUPT_KEYS_H
-
-struct interrupt_keys_button {
- /* Configuration parameters */
- int code; /* input event code (KEY_*, SW_*) */
- int irq;
- int active_low;
- char *desc;
- int type; /* input event type (EV_KEY, EV_SW) */
- int wakeup; /* configure the interrupt source as a wake-up
- * source */
- int debounce_interval; /* debounce ticks interval in msecs */
- bool can_disable;
-};
-
-struct interrupt_keys_platform_data {
- struct interrupt_keys_button *int_buttons;
- int nbuttons;
- unsigned int rep:1; /* enable input subsystem auto repeat */
- int (*enable)(struct device *dev);
- void (*disable)(struct device *dev);
-};
-
-#endif
diff --git a/include/linux/nct1008.h b/include/linux/nct1008.h
index 0a517f1d6d89..9227f4ad82f4 100644
--- a/include/linux/nct1008.h
+++ b/include/linux/nct1008.h
@@ -31,6 +31,8 @@
struct nct1008_data;
+enum nct1008_chip { NCT1008, NCT72 };
+
struct nct1008_platform_data {
bool supported_hwrev;
bool ext_range;
@@ -56,6 +58,7 @@ struct nct1008_data {
u8 config;
s8 *limits;
u8 limits_sz;
+ enum nct1008_chip chip;
void (*alarm_fn)(bool raised);
struct regulator *nct_reg;
long current_lo_limit;
diff --git a/include/linux/nvhost.h b/include/linux/nvhost.h
index da5e1e6862c6..82bb884dfbbd 100644
--- a/include/linux/nvhost.h
+++ b/include/linux/nvhost.h
@@ -32,6 +32,12 @@ struct nvhost_master;
#define NVHOST_MODULE_MAX_POWERGATE_IDS 2
#define NVHOST_MODULE_NO_POWERGATE_IDS .powergate_ids = {-1, -1}
#define NVHOST_DEFAULT_CLOCKGATE_DELAY .clockgate_delay = 25
+#define NVHOST_NAME_SIZE 24
+
+struct nvhost_device_id {
+ char name[NVHOST_NAME_SIZE];
+ unsigned long driver_data;
+};
struct nvhost_clock {
char *name;
@@ -46,7 +52,11 @@ enum nvhost_device_powerstate_t {
};
struct nvhost_device {
- const char *name; /* Device name */
+ /* device name: its format is of type -
+ * <name><ip-version>.<instance>
+ * e.g.: gr3d01 = gr3d ip version 01 used in tegra2
+ * no instance number means hardware supports single instance */
+ const char *name;
struct device dev; /* Linux device struct */
int id; /* Separates clients of same hw */
int index; /* Hardware channel number */
@@ -64,6 +74,7 @@ struct nvhost_device {
bool exclusive; /* True if only one user at a time */
bool keepalive; /* Do not power gate when opened */
bool waitbasesync; /* Force sync of wait bases */
+ bool powerup_reset; /* Do a reset after power un-gating */
int powergate_ids[NVHOST_MODULE_MAX_POWERGATE_IDS];
bool can_powergate; /* True if module can be power gated */
@@ -81,24 +92,6 @@ struct nvhost_device {
struct list_head client_list; /* List of clients and rate requests */
struct nvhost_channel *channel; /* Channel assigned for the module */
-
- /* Allocates a context handler for the device */
- struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
- u32 waitbase, struct nvhost_channel *ch);
- /* Preparing for power off. Used for context save. */
- int (*prepare_poweroff)(struct nvhost_device *dev);
- /* Finalize power on. Can be used for context restore. */
- void (*finalize_poweron)(struct nvhost_device *dev);
- /* Device is busy. */
- void (*busy)(struct nvhost_device *);
- /* Device is idle. */
- void (*idle)(struct nvhost_device *);
- /* Device is going to be suspended */
- void (*suspend)(struct nvhost_device *);
- /* Device is initialized */
- void (*init)(struct nvhost_device *dev);
- /* Device is de-initialized. */
- void (*deinit)(struct nvhost_device *dev);
};
/* Register device to nvhost bus */
@@ -110,12 +103,39 @@ extern void nvhost_device_unregister(struct nvhost_device *);
extern struct bus_type nvhost_bus_type;
struct nvhost_driver {
- int (*probe)(struct nvhost_device *);
+ int (*probe)(struct nvhost_device *, struct nvhost_device_id *);
int (*remove)(struct nvhost_device *);
void (*shutdown)(struct nvhost_device *);
int (*suspend)(struct nvhost_device *, pm_message_t state);
int (*resume)(struct nvhost_device *);
struct device_driver driver;
+
+ struct nvhost_device_id *id_table;
+
+ /* Finalize power on. Can be used for context restore. */
+ void (*finalize_poweron)(struct nvhost_device *dev);
+
+ /* Device is busy. */
+ void (*busy)(struct nvhost_device *);
+
+ /* Device is idle. */
+ void (*idle)(struct nvhost_device *);
+
+ /* Device is going to be suspended */
+ void (*suspend_ndev)(struct nvhost_device *);
+
+ /* Device is initialized */
+ void (*init)(struct nvhost_device *dev);
+
+ /* Device is de-initialized. */
+ void (*deinit)(struct nvhost_device *dev);
+
+ /* Preparing for power off. Used for context save. */
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+
+ /* Allocates a context handler for the device */
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
};
extern int nvhost_driver_register(struct nvhost_driver *);
@@ -127,7 +147,7 @@ extern struct resource *nvhost_get_resource_byname(struct nvhost_device *,
unsigned int, const char *);
extern int nvhost_get_irq_byname(struct nvhost_device *, const char *);
-#define to_nvhost_device(x) container_of((x), struct nvhost_device, dev)
+#define to_nvhost_device(x) container_of((x), struct nvhost_device, dev)
#define to_nvhost_driver(drv) (container_of((drv), struct nvhost_driver, \
driver))
diff --git a/arch/arm/mach-tegra/include/mach/nvmap.h b/include/linux/nvmap.h
index 88f913fc29dd..bea59694ad27 100644
--- a/arch/arm/mach-tegra/include/mach/nvmap.h
+++ b/include/linux/nvmap.h
@@ -1,9 +1,9 @@
/*
- * arch/arm/mach-tegra/include/mach/nvmap.h
+ * include/linux/nvmap.h
*
* structure declarations for nvmem and nvmap user-space ioctls
*
- * Copyright (c) 2009-2011, NVIDIA Corporation.
+ * Copyright (c) 2009-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 as published by
@@ -138,6 +138,9 @@ int nvmap_patch_word(struct nvmap_client *client,
struct nvmap_handle *patch,
u32 patch_offset, u32 patch_value);
+struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
+ unsigned long id);
+
struct nvmap_platform_carveout {
const char *name;
unsigned int usage_mask;
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 27bb05aae70d..6e25b3c1fc39 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -146,6 +146,15 @@ static inline void platform_set_drvdata(struct platform_device *pdev, void *data
dev_set_drvdata(&pdev->dev, data);
}
+/* module_platform_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit. This eliminates a lot of
+ * boilerplate. Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_platform_driver(__platform_driver) \
+ module_driver(__platform_driver, platform_driver_register, \
+ platform_driver_unregister)
+
extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
int (*probe)(struct platform_device *),
struct resource *res, unsigned int n_res,
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 9fce3c8eb40c..6986d16aeca8 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -43,7 +43,13 @@ struct reg_default {
/**
* Configuration for the register map of a device.
*
+ * @name: Optional name of the regmap. Useful when a device has multiple
+ * register regions.
+ *
* @reg_bits: Number of bits in a register address, mandatory.
+ * @reg_stride: The register address stride. Valid register addresses are a
+ * multiple of this value. If set to 0, a value of 1 will be
+ * used.
* @pad_bits: Number of bits of padding between register and value.
* @val_bits: Number of bits in a register value, mandatory.
*
@@ -74,7 +80,10 @@ struct reg_default {
* @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
*/
struct regmap_config {
+ const char *name;
+
int reg_bits;
+ int reg_stride;
int pad_bits;
int val_bits;
@@ -94,18 +103,21 @@ struct regmap_config {
u8 write_flag_mask;
};
-typedef int (*regmap_hw_write)(struct device *dev, const void *data,
+typedef int (*regmap_hw_write)(void *context, const void *data,
size_t count);
-typedef int (*regmap_hw_gather_write)(struct device *dev,
+typedef int (*regmap_hw_gather_write)(void *context,
const void *reg, size_t reg_len,
const void *val, size_t val_len);
-typedef int (*regmap_hw_read)(struct device *dev,
+typedef int (*regmap_hw_read)(void *context,
const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_size);
+typedef void (*regmap_hw_free_context)(void *context);
/**
* Description of a hardware bus for the register map infrastructure.
*
+ * @fast_io: Register IO is fast. Use a spinlock instead of a mutex
+ * to perform locking.
* @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device.
@@ -115,27 +127,37 @@ typedef int (*regmap_hw_read)(struct device *dev,
* a read.
*/
struct regmap_bus {
+ bool fast_io;
regmap_hw_write write;
regmap_hw_gather_write gather_write;
regmap_hw_read read;
+ regmap_hw_free_context free_context;
u8 read_flag_mask;
};
struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus,
+ void *bus_context,
const struct regmap_config *config);
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config);
struct regmap *regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config);
+struct regmap *regmap_init_mmio(struct device *dev,
+ void __iomem *regs,
+ const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
+ void *bus_context,
const struct regmap_config *config);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config);
struct regmap *devm_regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config);
+struct regmap *devm_regmap_init_mmio(struct device *dev,
+ void __iomem *regs,
+ const struct regmap_config *config);
void regmap_exit(struct regmap *map);
int regmap_reinit_cache(struct regmap *map,
@@ -157,8 +179,11 @@ int regmap_update_bits_lazy(struct regmap *map, unsigned int reg,
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
+int regmap_get_val_bytes(struct regmap *map);
int regcache_sync(struct regmap *map);
+int regcache_sync_region(struct regmap *map, unsigned int min,
+ unsigned int max);
void regcache_cache_only(struct regmap *map, bool enable);
void regcache_cache_bypass(struct regmap *map, bool enable);
void regcache_mark_dirty(struct regmap *map);
diff --git a/include/linux/regulator/gpio-switch-regulator.h b/include/linux/regulator/gpio-switch-regulator.h
deleted file mode 100644
index 68776b93ef00..000000000000
--- a/include/linux/regulator/gpio-switch-regulator.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2011, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef _GPIO_SWITCH_REGULATOR_H
-#define _GPIO_SWITCH_REGULATOR_H
-
-#include <linux/regulator/machine.h>
-
-/*
- * struct gpio_switch_regulator_subdev_data - Gpio switch regulator subdevice
- * data.
- *
- * Subdevice data to register a gpio regulator switch device driver.
- *
- * @regulator_name: The name of regulator.
- * @input_supply: Input supply name.
- * @id: The id of the switch.
- * @gpio_nr: Gpio nr which controls this switch.
- * @active_low: true if making gpio low makes voltage output enable.
- * @init_state: 1 if init_state should be active.
- * @voltages: Possible voltages to set at output. The values are in millivolt.
- * @n_voltages: Number of voltages.
- * @num_consumer_supplies: Number of cosumer supplies.
- * @consumer_supplies: List of consumer spllies.
- */
-struct gpio_switch_regulator_subdev_data {
- const char *regulator_name;
- const char *input_supply;
- int id;
- int gpio_nr;
- int active_low;
- int pin_group;
- int init_state;
- int *voltages;
- unsigned n_voltages;
- struct regulator_consumer_supply *consumer_supplies;
- int num_consumer_supplies;
- struct regulation_constraints constraints;
- int (*enable_rail)(struct gpio_switch_regulator_subdev_data *pdata);
- int (*disable_rail)(struct gpio_switch_regulator_subdev_data *pdata);
-
-};
-
-/**
- * gpio_switch_regulator_platform_data - platform data for gpio_switch_regulator
- * @num_subdevs: number of regulators used
- * @subdevs: pointer to regulators used
- */
-struct gpio_switch_regulator_platform_data {
- int num_subdevs;
- struct gpio_switch_regulator_subdev_data **subdevs;
-};
-
-#endif
diff --git a/include/linux/regulator/max8973-regulator.h b/include/linux/regulator/max8973-regulator.h
new file mode 100644
index 000000000000..4b86e88b028e
--- /dev/null
+++ b/include/linux/regulator/max8973-regulator.h
@@ -0,0 +1,77 @@
+/*
+ * max8973-regulator.h -- MAXIM 8973 regulator
+ *
+ * Interface for regulator driver for MAXIM 8973 DC-DC step-down
+ * switching regulator.
+ *
+ * Copyright (C) 2012 NVIDIA Corporation
+
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_REGULATOR_MAX8973_H
+#define __LINUX_REGULATOR_MAX8973_H
+
+/*
+ * Control flags for configuration of the device.
+ * Client need to pass this information with ORed
+ */
+#define MAX8973_CONTROL_REMOTE_SENSE_ENABLE 0x00000001
+#define MAX8973_CONTROL_FALLING_SLEW_RATE_ENABLE 0x00000002
+#define MAX8973_CONTROL_OUTPUT_ACTIVE_DISCH_ENABLE 0x00000004
+#define MAX8973_CONTROL_BIAS_ENABLE 0x00000008
+#define MAX8973_CONTROL_PULL_DOWN_ENABLE 0x00000010
+#define MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE 0x00000020
+
+#define MAX8973_CONTROL_SLEW_RATE_12_5mV_PER_US 0x00000000
+#define MAX8973_CONTROL_SLEW_RATE_25mV_PER_US 0x00000100
+#define MAX8973_CONTROL_SLEW_RATE_50mV_PER_US 0x00000200
+#define MAX8973_CONTROL_SLEW_RATE_200MV_PER_US 0x00000300
+
+#define MAX8973_CONTROL_CLKADV_TRIP_DISABLED 0x00000000
+#define MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US 0x00010000
+#define MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US 0x00020000
+#define MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US_HIST_DIS 0x00030000
+
+#define MAX8973_CONTROL_INDUCTOR_VALUE_NOMINAL 0x00000000
+#define MAX8973_CONTROL_INDUCTOR_VALUE_MINUS_30_PER 0x00100000
+#define MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_30_PER 0x00200000
+#define MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER 0x00300000
+
+/*
+ * struct max8973_regulator_platform_data - max8973 regulator platform data.
+ *
+ * @reg_init_data: The regulator init data.
+ * @control_flags: Control flags which are ORed value of above flags to
+ * configure device.
+ * @enable_ext_control: Enable the voltage enable/disable through external
+ * control signal from EN input pin. If it is false then
+ * voltage output will be enabled/disabled through EN bit of
+ * device register.
+ * @dvs_gpio: GPIO for dvs. It should be -1 if this is tied with fixed logic.
+ * @dvs_def_state: Default state of dvs. 1 if it is high else 0.
+ */
+struct max8973_regulator_platform_data {
+ struct regulator_init_data *reg_init_data;
+ unsigned long control_flags;
+ bool enable_ext_control;
+ int dvs_gpio;
+ unsigned dvs_def_state:1;
+};
+
+#endif /* __LINUX_REGULATOR_MAX8973_H */
diff --git a/include/linux/regulator/tps6238x0-regulator.h b/include/linux/regulator/tps6238x0-regulator.h
new file mode 100644
index 000000000000..d7c4edc5b101
--- /dev/null
+++ b/include/linux/regulator/tps6238x0-regulator.h
@@ -0,0 +1,46 @@
+/*
+ * tps6238x0-regulator.h -- TI TPS623850/TPS623860/TPS623870
+ *
+ * Interface for regulator driver for TI TPS623850/TPS623860/TPS623870
+ * Processor core supply
+ *
+ * Copyright (C) 2012 NVIDIA Corporation
+
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_REGULATOR_TPS6238X0_H
+#define __LINUX_REGULATOR_TPS6238X0_H
+
+/*
+ * struct tps6238x0_regulator_platform_data - tps62360 regulator platform data.
+ *
+ * @init_data: The regulator init data.
+ * @en_internal_pulldn: internal pull down enable or not.
+ * @vsel_gpio: Gpio number for vsel. It should be -1 if this is tied with
+ * fixed logic.
+ * @vsel_def_state: Default state of vsel. 1 if it is high else 0.
+ */
+struct tps6238x0_regulator_platform_data {
+ struct regulator_init_data *init_data;
+ bool en_internal_pulldn;
+ int vsel_gpio;
+ int vsel_def_state;
+};
+
+#endif /* __LINUX_REGULATOR_TPS6238X0_H */
diff --git a/include/linux/smb349-charger.h b/include/linux/smb349-charger.h
index 6dbec61034ed..089f3976dbbe 100644
--- a/include/linux/smb349-charger.h
+++ b/include/linux/smb349-charger.h
@@ -26,6 +26,7 @@
#include <linux/regulator/machine.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
+#include <linux/usb/otg.h>
struct smb349_charger_platform_data {
int regulator_id;
@@ -44,6 +45,7 @@ enum charging_states {
};
enum charger_type {
+ NONE,
AC,
USB,
};
diff --git a/include/linux/tegra_audio.h b/include/linux/tegra_audio.h
index 904dde998fc4..3975913a5206 100644
--- a/include/linux/tegra_audio.h
+++ b/include/linux/tegra_audio.h
@@ -78,7 +78,7 @@ struct dam_srate {
#ifdef CONFIG_SND_SOC_TEGRA
extern bool tegra_is_voice_call_active();
#else
-inline bool tegra_is_voice_call_active()
+static inline bool tegra_is_voice_call_active()
{
return false;
}
diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h
index 0f559ae411c8..c13dc0c0f4c3 100644
--- a/include/linux/wl12xx.h
+++ b/include/linux/wl12xx.h
@@ -48,8 +48,8 @@ enum {
};
struct wl12xx_platform_data {
- void (*set_power)(bool enable);
- void (*set_carddetect)(bool enable);
+ int (*set_power)(int power_on);
+ int (*set_carddetect)(int val);
/* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
int irq;
bool use_eeprom;
diff --git a/include/media/nvc.h b/include/media/nvc.h
index 9b24b0ea019e..0f9bb9bdf3d7 100644
--- a/include/media/nvc.h
+++ b/include/media/nvc.h
@@ -275,6 +275,7 @@ struct nvc_gpio {
unsigned gpio; /* system GPIO number */
bool own; /* gets set if driver initializes */
bool active_high; /* used for GP GPIOs */
+ bool valid; /* set if struct data is valid */
bool flag; /* scratch flag for driver implementation */
};
diff --git a/include/media/ov5640.h b/include/media/ov5640.h
new file mode 100644
index 000000000000..edae5fe4b1a8
--- /dev/null
+++ b/include/media/ov5640.h
@@ -0,0 +1,64 @@
+/*
+ * ov5640.h - 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_H__
+#define __OV5640_H__
+
+#include <linux/ioctl.h> /* For IOCTL macros */
+
+#define OV5640_IOCTL_SET_SENSOR_MODE _IOW('o', 1, struct ov5640_mode)
+#define OV5640_IOCTL_GET_SENSOR_STATUS _IOR('o', 2, __u8)
+#define OV5640_IOCTL_GET_CONFIG _IOR('o', 3, struct ov5640_config)
+#define OV5640_IOCTL_SET_FPOSITION _IOW('o', 4, __u32)
+#define OV5640_IOCTL_POWER_LEVEL _IOW('o', 5, __u32)
+#define OV5640_IOCTL_GET_AF_STATUS _IOR('o', 6, __u8)
+#define OV5640_IOCTL_SET_AF_MODE _IOR('o', 7, __u8)
+
+#define OV5640_POWER_LEVEL_OFF 0
+#define OV5640_POWER_LEVEL_ON 1
+#define OV5640_POWER_LEVEL_SUS 2
+
+struct ov5640_mode {
+ int xres;
+ int yres;
+};
+
+struct ov5640_config {
+ __u32 settle_time;
+ __u32 pos_low;
+ __u32 pos_high;
+ float focal_length;
+ float fnumber;
+};
+
+enum {
+ OV5640_AF_INIFINITY,
+ OV5640_AF_TRIGGER,
+};
+
+#ifdef __KERNEL__
+struct ov5640_platform_data {
+ int (*power_on)(void);
+ int (*power_off)(void);
+
+};
+#endif /* __KERNEL__ */
+
+#endif /* __OV5640_H__ */
diff --git a/include/media/ov5650.h b/include/media/ov5650.h
index 5c4a87cfbe8d..a8f70a592d89 100644
--- a/include/media/ov5650.h
+++ b/include/media/ov5650.h
@@ -32,6 +32,7 @@
#define OV5650_IOCTL_SET_GROUP_HOLD _IOW('o', 8, struct ov5650_ae)
#define OV5650_IOCTL_SET_CAMERA_MODE _IOW('o', 10, __u32)
#define OV5650_IOCTL_SYNC_SENSORS _IOW('o', 11, __u32)
+#define OV5650_IOCTL_GET_SENSORDATA _IOR('o', 12, struct ov5650_sensordata)
/* OV5650 registers */
#define OV5650_SRM_GRUP_ACCESS (0x3212)
@@ -64,6 +65,11 @@ enum ov5650_test_pattern {
TEST_PATTERN_CHECKERBOARD
};
+struct ov5650_sensordata {
+ __u32 fuse_id_size;
+ __u8 fuse_id[16];
+};
+
struct ov5650_mode {
int xres;
int yres;
diff --git a/include/media/sh532u.h b/include/media/sh532u.h
index 19da2070b70f..e9653e68b21f 100644
--- a/include/media/sh532u.h
+++ b/include/media/sh532u.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -19,25 +19,23 @@
#ifndef __SH532U_H__
#define __SH532U_H__
+#include <media/nvc.h>
#include <media/nvc_focus.h>
+/* See notes in the nvc.h file on the GPIO usage */
+enum sh532u_gpio {
+ SH532U_GPIO_RESET = 0,
+ SH532U_GPIO_I2CMUX,
+ SH532U_GPIO_GP1,
+ SH532U_GPIO_GP2,
+ SH532U_GPIO_GP3,
+};
-struct sh532u_platform_data {
- int cfg;
- int num;
- int sync;
- const char *dev_name;
- struct nvc_focus_nvc (*nvc);
- struct nvc_focus_cap (*cap);
- struct sh532u_pdata_info (*info);
- __u8 i2c_addr_rom;
- unsigned gpio_reset;
-/* 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.
- */
- unsigned gpio_en;
+/* The enumeration must be in the order the regulators are to be enabled */
+/* See Power Requirements note in the driver */
+enum sh532u_vreg {
+ SH532U_VREG_DVDD = 0,
+ SH532U_VREG_AVDD,
};
struct sh532u_pdata_info {
@@ -50,6 +48,18 @@ struct sh532u_pdata_info {
__u32 focus_hyper_div;
};
+struct sh532u_platform_data {
+ unsigned cfg;
+ unsigned num;
+ unsigned sync;
+ const char *dev_name;
+ unsigned gpio_count; /* see nvc.h GPIO notes */
+ struct nvc_gpio_pdata *gpio; /* see nvc.h GPIO notes */
+ struct nvc_focus_nvc (*nvc);
+ struct nvc_focus_cap (*cap);
+ struct sh532u_pdata_info (*info);
+ __u8 i2c_addr_rom;
+};
/* Register Definition : Sany Driver IC */
/* EEPROM addresses */
diff --git a/include/media/tegra_camera.h b/include/media/tegra_camera.h
index d7d08bd9a99b..9dea1485781d 100644
--- a/include/media/tegra_camera.h
+++ b/include/media/tegra_camera.h
@@ -23,11 +23,14 @@ enum {
TEGRA_CAMERA_MODULE_ISP = 0,
TEGRA_CAMERA_MODULE_VI,
TEGRA_CAMERA_MODULE_CSI,
+ TEGRA_CAMERA_MODULE_EMC,
+ TEGRA_CAMERA_MODULE_MAX
};
enum {
TEGRA_CAMERA_VI_CLK,
TEGRA_CAMERA_VI_SENSOR_CLK,
+ TEGRA_CAMERA_EMC_CLK
};
struct tegra_camera_clk_info {
diff --git a/include/trace/events/nvhost.h b/include/trace/events/nvhost.h
index 4c44cdc99f98..4bb79e30fc19 100644
--- a/include/trace/events/nvhost.h
+++ b/include/trace/events/nvhost.h
@@ -138,7 +138,28 @@ TRACE_EVENT(nvhost_channel_write_cmdbuf,
__entry->words, __entry->offset)
);
-TRACE_EVENT(nvhost_channel_write_cmdbuf_data,
+TRACE_EVENT(nvhost_cdma_push,
+ TP_PROTO(const char *name, u32 op1, u32 op2),
+
+ TP_ARGS(name, op1, op2),
+
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ __field(u32, op1)
+ __field(u32, op2)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->op1 = op1;
+ __entry->op2 = op2;
+ ),
+
+ TP_printk("name=%s, op1=%08x, op2=%08x",
+ __entry->name, __entry->op1, __entry->op2)
+);
+
+TRACE_EVENT(nvhost_cdma_push_gather,
TP_PROTO(const char *name, u32 mem_id,
u32 words, u32 offset, void *cmdbuf),
@@ -432,6 +453,48 @@ TRACE_EVENT(nvhost_wait_cdma,
TP_printk("name=%s, event=%d", __entry->name, __entry->eventid)
);
+TRACE_EVENT(nvhost_syncpt_update_min,
+ TP_PROTO(u32 id, u32 val),
+
+ TP_ARGS(id, val),
+
+ TP_STRUCT__entry(
+ __field(u32, id)
+ __field(u32, val)
+ ),
+
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->val = val;
+ ),
+
+ TP_printk("id=%d, val=%d", __entry->id, __entry->val)
+);
+
+TRACE_EVENT(nvhost_syncpt_wait_check,
+ TP_PROTO(u32 mem_id, u32 offset, u32 syncpt_id, u32 val),
+
+ TP_ARGS(mem_id, offset, syncpt_id, val),
+
+ TP_STRUCT__entry(
+ __field(u32, mem_id)
+ __field(u32, offset)
+ __field(u32, syncpt_id)
+ __field(u32, val)
+ ),
+
+ TP_fast_assign(
+ __entry->mem_id = mem_id;
+ __entry->offset = offset;
+ __entry->syncpt_id = syncpt_id;
+ __entry->val = val;
+ ),
+
+ TP_printk("mem_id=%08x, offset=%05x, id=%d, val=%d",
+ __entry->mem_id, __entry->offset,
+ __entry->syncpt_id, __entry->val)
+);
+
#endif /* _TRACE_NVHOST_H */
/* This part must be outside protection */
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 9c9699a2b457..5b503e9b661c 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -41,6 +41,11 @@ DEFINE_EVENT(cpu, cpu_idle,
#define PWR_EVENT_EXIT -1
enum {
+ CPU_SUSPEND_START,
+ CPU_SUSPEND_DONE
+};
+
+enum {
POWER_CPU_UP_START,
POWER_CPU_UP_DONE,
POWER_CPU_DOWN_START,
@@ -59,6 +64,23 @@ enum {
#endif
+TRACE_EVENT(cpu_suspend,
+
+ TP_PROTO(unsigned int state),
+
+ TP_ARGS(state),
+
+ TP_STRUCT__entry(
+ __field(u32, state)
+ ),
+
+ TP_fast_assign(
+ __entry->state = state;
+ ),
+
+ TP_printk("state=%lu", (unsigned long)__entry->state)
+);
+
TRACE_EVENT(cpu_hotplug,
TP_PROTO(unsigned int cpu_id, int state),
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h
index 12fbf43524e9..d69738280ffa 100644
--- a/include/trace/events/regmap.h
+++ b/include/trace/events/regmap.h
@@ -139,6 +139,42 @@ TRACE_EVENT(regcache_sync,
__get_str(type), __get_str(status))
);
+DECLARE_EVENT_CLASS(regmap_bool,
+
+ TP_PROTO(struct device *dev, bool flag),
+
+ TP_ARGS(dev, flag),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev) )
+ __field( int, flag )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __entry->flag = flag;
+ ),
+
+ TP_printk("%s flag=%d", __get_str(name),
+ (int)__entry->flag)
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_only,
+
+ TP_PROTO(struct device *dev, bool flag),
+
+ TP_ARGS(dev, flag)
+
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
+
+ TP_PROTO(struct device *dev, bool flag),
+
+ TP_ARGS(dev, flag)
+
+);
+
#endif /* _TRACE_REGMAP_H */
/* This part must be outside protection */
diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h
index f46074b1e559..76bb34b01af1 100644
--- a/include/video/tegra_dc_ext.h
+++ b/include/video/tegra_dc_ext.h
@@ -59,6 +59,7 @@
#define TEGRA_DC_EXT_FLIP_FLAG_INVERT_V (1 << 1)
#define TEGRA_DC_EXT_FLIP_FLAG_TILED (1 << 2)
#define TEGRA_DC_EXT_FLIP_FLAG_CURSOR (1 << 3)
+#define TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA (1 << 4)
struct tegra_dc_ext_flip_windowattr {
__s32 index;
@@ -91,8 +92,10 @@ struct tegra_dc_ext_flip_windowattr {
__u32 buff_id_u;
__u32 buff_id_v;
__u32 flags;
+ __u8 global_alpha; /* requires TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA */
/* Leave some wiggle room for future expansion */
- __u32 pad[5];
+ __u8 pad1[3];
+ __u32 pad2[4];
};
#define TEGRA_DC_EXT_FLIP_N_WINDOWS 3
diff --git a/security/tf_driver/s_version.h b/security/tf_driver/s_version.h
index 6244d3fe7e8d..ba4d48c6f417 100644
--- a/security/tf_driver/s_version.h
+++ b/security/tf_driver/s_version.h
@@ -33,12 +33,12 @@
*/
#define S_VERSION_OS "A" /* "A" for all Android */
-#define S_VERSION_PLATFORM "B" /* "B" for Tegra3 */
+#define S_VERSION_PLATFORM "A" /* "A" for Tegra2 */
/*
* This version number must be updated for each new release
*/
-#define S_VERSION_MAIN "01.03"
+#define S_VERSION_MAIN "01.07"
/*
* If this is a patch or engineering version use the following
diff --git a/security/tf_driver/tf_comm.c b/security/tf_driver/tf_comm.c
index 16915beb406d..ad45d31d80b9 100644
--- a/security/tf_driver/tf_comm.c
+++ b/security/tf_driver/tf_comm.c
@@ -208,6 +208,7 @@ struct tf_coarse_page_table *tf_alloc_coarse_page_table(
}
array->type = type;
+ array->ref_count = 0;
INIT_LIST_HEAD(&(array->list));
/* now allocate the actual page the page descriptor describes */
@@ -236,7 +237,7 @@ struct tf_coarse_page_table *tf_alloc_coarse_page_table(
*/
coarse_pg_table =
&(array->coarse_page_tables[i]);
- array->ref_count = 1;
+ array->ref_count++;
} else {
/*
* The other elements are added to the free list
@@ -455,12 +456,11 @@ u32 tf_get_l2_descriptor_common(u32 vaddr, struct mm_struct *mm)
/*
* Linux's pte doesn't keep track of TEX value.
* Have to jump to hwpte see include/asm/pgtable.h
- * (-2k before 2.6.38, then +2k)
*/
#ifdef PTE_HWTABLE_SIZE
- hwpte = (u32 *) (ptep+PTE_HWTABLE_PTRS);
+ hwpte = (u32 *) (ptep + PTE_HWTABLE_PTRS);
#else
- hwpte = (u32 *) (ptep-PTRS_PER_PTE);
+ hwpte = (u32 *) (ptep - PTRS_PER_PTE);
#endif
if (((*hwpte) & L2_DESCRIPTOR_ADDR_MASK) !=
((*ptep) & L2_DESCRIPTOR_ADDR_MASK))
@@ -839,52 +839,28 @@ int tf_fill_descriptor_table(
goto error;
}
}
- } else if (is_vmalloc_addr((void *)buffer_offset_vaddr)) {
- /* Kernel-space memory obtained through vmalloc */
- dprintk(KERN_INFO
- "tf_fill_descriptor_table: "
- "vmalloc'ed buffer starting at %p\n",
- (void *)buffer_offset_vaddr);
- for (j = page_shift; j < pages_to_get; j++) {
- struct page *page;
- void *addr =
- (void *)(buffer_offset_vaddr +
- (j - page_shift) * PAGE_SIZE);
- page = vmalloc_to_page(addr);
- if (page == NULL) {
- dprintk(KERN_ERR
- "tf_fill_descriptor_table: "
- "cannot map %p (vmalloc) "
- "to page\n",
- addr);
- ret = -EFAULT;
- goto error;
- }
- coarse_pg_table->descriptors[j] = (u32)page;
- get_page(page);
-
- /* change coarse page "page address" */
- tf_get_l2_page_descriptor(
- &coarse_pg_table->descriptors[j],
- flags,
- &init_mm);
- }
} else {
- /* Kernel-space memory given by a virtual address */
+ /* Kernel-space memory */
dprintk(KERN_INFO
"tf_fill_descriptor_table: "
- "buffer starting at virtual address %p\n",
+ "buffer starting at %p\n",
(void *)buffer_offset_vaddr);
for (j = page_shift; j < pages_to_get; j++) {
struct page *page;
void *addr =
(void *)(buffer_offset_vaddr +
(j - page_shift) * PAGE_SIZE);
- page = virt_to_page(addr);
+
+ if (is_vmalloc_addr(
+ (void *) buffer_offset_vaddr))
+ page = vmalloc_to_page(addr);
+ else
+ page = virt_to_page(addr);
+
if (page == NULL) {
dprintk(KERN_ERR
"tf_fill_descriptor_table: "
- "cannot map %p (virtual) "
+ "cannot map %p (vmalloc) "
"to page\n",
addr);
ret = -EFAULT;
@@ -1256,10 +1232,6 @@ static int tf_send_recv(struct tf_comm *comm,
dprintk(KERN_INFO "[pid=%d] tf_send_recv(%p)\n",
current->pid, command);
-#ifdef CONFIG_TF_ZEBRA
- tf_clock_timer_start();
-#endif
-
#ifdef CONFIG_FREEZER
saved_flags = current->flags;
current->flags |= PF_FREEZER_NOSIG;
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c
index ad44b46c2067..8f31bf35f90a 100644
--- a/security/tf_driver/tf_device.c
+++ b/security/tf_driver/tf_device.c
@@ -87,7 +87,7 @@ static long tf_device_ioctl(
/*
* Implements the device shutdown callback.
*/
-static int tf_device_shutdown(void);
+static void tf_device_shutdown(void);
/*
@@ -99,7 +99,7 @@ static int tf_device_suspend(void);
/*
* Implements the device resume callback.
*/
-static int tf_device_resume(void);
+static void tf_device_resume(void);
/*---------------------------------------------------------------------------
@@ -393,7 +393,7 @@ static int __init tf_device_register(void)
}
#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
- error = tf_self_test_post_init(&(dev_stats->kobj));
+ error = tf_self_test_post_init(&(g_tf_dev.kobj));
/* N.B. error > 0 indicates a POST failure, which will not
prevent the module from loading. */
if (error < 0) {
@@ -762,11 +762,10 @@ exit:
/*----------------------------------------------------------------------------*/
-static int tf_device_shutdown(void)
+static void tf_device_shutdown(void)
{
-
- return tf_power_management(&g_tf_dev.sm,
- TF_POWER_OPERATION_SHUTDOWN);
+ if (0 > tf_power_management(&g_tf_dev.sm, TF_POWER_OPERATION_SHUTDOWN))
+ dprintk(KERN_ERR "tf_device_shutdown failing\n");
}
/*----------------------------------------------------------------------------*/
@@ -781,10 +780,10 @@ static int tf_device_suspend(void)
/*----------------------------------------------------------------------------*/
-static int tf_device_resume(void)
+static void tf_device_resume(void)
{
- return tf_power_management(&g_tf_dev.sm,
- TF_POWER_OPERATION_RESUME);
+ if (0 > tf_power_management(&g_tf_dev.sm, TF_POWER_OPERATION_RESUME))
+ dprintk(KERN_ERR "tf_device_resume failing\n");
}
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index ad760f90053d..a8042e14f5de 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -704,10 +704,11 @@ void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
channels_max = 2;
for (i = 0; i < eld->sad_count; i++) {
struct cea_sad *a = &eld->sad[i];
+
rates |= a->rates;
- if (a->channels > channels_max)
- channels_max = a->channels;
if (a->format == AUDIO_CODING_TYPE_LPCM) {
+ if (a->channels > channels_max)
+ channels_max = a->channels;
if (a->sample_bits & AC_SUPPCM_BITS_20) {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
if (maxbps < 20)
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index fcc32f590874..5942395099ad 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1112,6 +1112,12 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
#if defined(CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA) && defined(CONFIG_TEGRA_DC)
if (codec->preset->id == 0x10de0020) {
int err = 0;
+
+ if (substream->runtime->channels == 2)
+ tegra_hdmi_audio_null_sample_inject(true);
+ else
+ tegra_hdmi_audio_null_sample_inject(false);
+
/* Set hdmi:audio freq and source selection*/
err = tegra_hdmi_setup_audio_freq_source(
substream->runtime->rate, HDA);
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 2eaef5b52e08..d80b7bbff2e8 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -35,8 +35,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
-snd-soc-tlv320aic326x-objs := tlv320aic326x.o tlv320aic326x_minidsp_config.o
-snd-soc-tlv320aic326x-objs += tlv320aic326x_mini-dsp.o aic326x_tiload.o
+snd-soc-tlv320aic326x-objs := tlv320aic326x.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c
index 00aa4d4ce7d7..07615dc5ebd7 100644
--- a/sound/soc/codecs/aic326x_tiload.c
+++ b/sound/soc/codecs/aic326x_tiload.c
@@ -61,7 +61,8 @@ static void aic3262_dump_page(struct i2c_client *i2c, u8 page);
/* externs */
extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
-extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value);
+extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value);
int aic3262_driver_init(struct snd_soc_codec *codec);
/************** Dynamic aic3262 driver, TI LOAD support ***************/
@@ -236,7 +237,7 @@ static ssize_t tiload_write(struct file *file, const char __user * buf,
return i2c_master_send(i2c, wr_data, count);
}
-static int tiload_ioctl( struct file *filp,
+static long tiload_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
int num = 0;
diff --git a/sound/soc/codecs/base_main_Rate48_pps_driver.h b/sound/soc/codecs/base_main_Rate48_pps_driver.h
index 4d6f227cc42e..dff91858940e 100644
--- a/sound/soc/codecs/base_main_Rate48_pps_driver.h
+++ b/sound/soc/codecs/base_main_Rate48_pps_driver.h
@@ -16,17 +16,6 @@ static control base_speaker_SRS_VOLUME_controls[] = {
static char * base_speaker_SRS_VOLUME_control_names[] = {
};
-/*//INSTRUCTIONS & COEFFICIENTS
-typedef struct {
- u8 reg_off;
- u8 reg_val;
-} reg_value;*/
-
-static char * base_speaker_SRS_REG_Section_names[] = {
- "miniDSP_A_reg_values",
- "miniDSP_D_reg_values",
-};
-
reg_value base_speaker_SRS_REG_init_Section_program[] = {
{ 0,0x0},
{ 0x7F,0x00},
diff --git a/sound/soc/codecs/rt5639.c b/sound/soc/codecs/rt5639.c
index 06c8451a27c8..c9b14e9f0bc1 100644
--- a/sound/soc/codecs/rt5639.c
+++ b/sound/soc/codecs/rt5639.c
@@ -421,8 +421,18 @@ static int rt5639_readable_register(
int rt5639_headset_detect(struct snd_soc_codec *codec, int jack_insert)
{
int jack_type;
+ int sclk_src;
if (jack_insert) {
+ if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+ snd_soc_write(codec, RT5639_PWR_ANLG1, 0x2004);
+ snd_soc_write(codec, RT5639_MICBIAS, 0x3830);
+ snd_soc_write(codec, RT5639_DUMMY1 , 0x3701);
+ }
+ sclk_src = snd_soc_read(codec, RT5639_GLB_CLK) &
+ RT5639_SCLK_SRC_MASK;
+ snd_soc_update_bits(codec, RT5639_GLB_CLK,
+ RT5639_SCLK_SRC_MASK, 0x3 << RT5639_SCLK_SRC_SFT);
snd_soc_update_bits(codec, RT5639_PWR_ANLG1,
RT5639_PWR_LDO2, RT5639_PWR_LDO2);
snd_soc_update_bits(codec, RT5639_PWR_ANLG2,
@@ -434,13 +444,15 @@ int rt5639_headset_detect(struct snd_soc_codec *codec, int jack_insert)
RT5639_PWR_MB_PU | RT5639_PWR_CLK25M_PU);
snd_soc_update_bits(codec, RT5639_DUMMY1,
0x1, 0x1);
- msleep(50);
+ msleep(100);
if (snd_soc_read(codec, RT5639_IRQ_CTRL2) & 0x8)
jack_type = RT5639_HEADPHO_DET;
else
jack_type = RT5639_HEADSET_DET;
snd_soc_update_bits(codec, RT5639_IRQ_CTRL2,
RT5639_MB1_OC_CLR, 0);
+ snd_soc_update_bits(codec, RT5639_GLB_CLK,
+ RT5639_SCLK_SRC_MASK, sclk_src);
} else {
snd_soc_update_bits(codec, RT5639_MICBIAS,
RT5639_MIC1_OVCD_MASK,
@@ -1186,8 +1198,6 @@ static int spk_event(struct snd_soc_dapm_widget *w,
static int hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
-
switch (event) {
case SND_SOC_DAPM_POST_PMU:
printk("hp_event --SND_SOC_DAPM_POST_PMU\n");
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 4f50b39cb48a..8407c638cf8a 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -25,7 +25,7 @@
#include <sound/tlv.h>
#include "rt5640.h"
-#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
+#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
#include "rt5640-dsp.h"
#endif
@@ -422,8 +422,18 @@ static int rt5640_readable_register(
int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
{
int jack_type;
+ int sclk_src;
if (jack_insert) {
+ if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+ snd_soc_write(codec, RT5640_PWR_ANLG1, 0x2004);
+ snd_soc_write(codec, RT5640_MICBIAS, 0x3830);
+ snd_soc_write(codec, RT5640_DUMMY1 , 0x3701);
+ }
+ sclk_src = snd_soc_read(codec, RT5640_GLB_CLK) &
+ RT5640_SCLK_SRC_MASK;
+ snd_soc_update_bits(codec, RT5640_GLB_CLK,
+ RT5640_SCLK_SRC_MASK, 0x3 << RT5640_SCLK_SRC_SFT);
snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
RT5640_PWR_LDO2, RT5640_PWR_LDO2);
snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
@@ -435,13 +445,15 @@ int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
RT5640_PWR_MB_PU | RT5640_PWR_CLK25M_PU);
snd_soc_update_bits(codec, RT5640_DUMMY1,
0x1, 0x1);
- msleep(50);
+ msleep(100);
if (snd_soc_read(codec, RT5640_IRQ_CTRL2) & 0x8)
jack_type = RT5640_HEADPHO_DET;
else
jack_type = RT5640_HEADSET_DET;
snd_soc_update_bits(codec, RT5640_IRQ_CTRL2,
RT5640_MB1_OC_CLR, 0);
+ snd_soc_update_bits(codec, RT5640_GLB_CLK,
+ RT5640_SCLK_SRC_MASK, sclk_src);
} else {
snd_soc_update_bits(codec, RT5640_MICBIAS,
RT5640_MIC1_OVCD_MASK,
@@ -1167,8 +1179,6 @@ static int spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- static unsigned int spkl_out_enable;
- static unsigned int spkr_out_enable;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -1194,9 +1204,6 @@ static int spk_event(struct snd_soc_dapm_widget *w,
static int hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
- static unsigned int hp_out_enable;
-
switch (event) {
case SND_SOC_DAPM_POST_PMU:
pr_info("hp_event --SND_SOC_DAPM_POST_PMU\n");
@@ -1808,9 +1815,8 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
ret |= RT5640_U_IF3;
break;
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
-
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
case RT5640_AIF3:
if (val == RT5640_IF_312 || val == RT5640_IF_321)
ret |= RT5640_U_IF1;
@@ -1910,8 +1916,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
RT5640_I2S_DL_MASK, val_len);
snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
}
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
if (dai_sel & RT5640_U_IF3) {
mask_clk = RT5640_I2S_BCLK_MS3_MASK | RT5640_I2S_PD3_MASK;
val_clk = bclk_ms << RT5640_I2S_BCLK_MS3_SFT |
@@ -1994,8 +2000,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
RT5640_I2S_DF_MASK, reg_val);
}
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
if (dai_sel & RT5640_U_IF3) {
snd_soc_update_bits(codec, RT5640_I2S3_SDP,
RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
@@ -2123,10 +2129,8 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
break;
case RT5640_PLL1_S_BCLK1:
case RT5640_PLL1_S_BCLK2:
-
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
-
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
case RT5640_PLL1_S_BCLK3:
#endif
@@ -2346,8 +2350,7 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640_reg_init(codec);
#endif
-
-#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
+#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
rt5640_register_dsp(codec);
#endif
@@ -2446,8 +2449,8 @@ struct snd_soc_dai_driver rt5640_dai[] = {
},
.ops = &rt5640_aif_dai_ops,
},
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
{
.name = "rt5640-aif3",
.id = RT5640_AIF3,
diff --git a/sound/soc/codecs/second_rate_pps_driver.h b/sound/soc/codecs/second_rate_pps_driver.h
index c6c128a027dd..9956c08bcd80 100644
--- a/sound/soc/codecs/second_rate_pps_driver.h
+++ b/sound/soc/codecs/second_rate_pps_driver.h
@@ -14,13 +14,6 @@ static control main44_VOLUME_controls[] = {
static char *main44_VOLUME_control_names[] = {
};
-
-
-static char *main44_REG_Section_names[] = {
- "miniDSP_A_reg_values",
- "miniDSP_D_reg_values",
-};
-
reg_value main44_REG_Section_init_program[] = {
{ 0,0x0},
{ 0x7F,0x00},
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 7c1bf5c04eb9..6173b3a5b082 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -8,12 +8,15 @@
* Author: Steve Chen, <schen@mvista.com>
* Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com>
* Copyright: (C) 2009 Texas Instruments, India
+ * Copyright: (C) 2009-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.
*/
+
+#include <asm/mach-types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
@@ -26,9 +29,34 @@
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
-
static struct snd_soc_codec_driver soc_codec_spdif_dit;
+static int spdif_probe(struct snd_soc_codec *codec) {
+ codec->dapm.idle_bias_off = 1;
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget spdif_dapm_widgets[] = {
+ SND_SOC_DAPM_VMID("spdif dummy Vmid"),
+};
+
+static int spdif_write(struct snd_soc_codec * codec, unsigned int reg,
+ unsigned int val){
+ return 0;
+}
+
+static int spdif_read(struct snd_soc_codec * codec, unsigned int reg){
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_spdif_dit1 = {
+ .probe = spdif_probe,
+ .dapm_widgets = spdif_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(spdif_dapm_widgets),
+ .read = spdif_read,
+ .write = spdif_write,
+};
+
static struct snd_soc_dai_driver dit_stub_dai = {
.name = "dit-hifi",
.playback = {
@@ -49,8 +77,12 @@ static struct snd_soc_dai_driver dit_stub_dai = {
static int spdif_dit_probe(struct platform_device *pdev)
{
- return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
- &dit_stub_dai, 1);
+ if(machine_is_kai() || machine_is_tegra_enterprise())
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_spdif_dit1, &dit_stub_dai, 1);
+ else
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_spdif_dit, &dit_stub_dai, 1);
}
static int spdif_dit_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c
index 8bbd295a3328..5d6b92904d56 100644
--- a/sound/soc/codecs/tlv320aic326x.c
+++ b/sound/soc/codecs/tlv320aic326x.c
@@ -81,9 +81,6 @@ static u8 aic3262_reg_ctl;
* This function reprograms the clock dividers etc. this flag can be used to
* disable this when the clock dividers are programmed by pps config file
*/
-static int soc_static_freq_config = 1;
-static struct aic3262_priv *aic3262_priv_data;
-static struct i2c_client *i2c_pdev;
static struct snd_soc_codec *aic3262_codec;
/*
@@ -849,7 +846,6 @@ static const struct aic3262_rate_divs aic3262_divs[] = {
static void aic3262_multi_i2s_dump_regs(struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
unsigned int counter;
DBG(KERN_INFO "#%s: Dai Active %d ASI%d REGS DUMP\n",
@@ -1965,7 +1961,7 @@ static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream,
* We can use this function to disable the DAC and ADC specific inputs from the
* individual ASI Ports of the Audio Codec.
*/
-static int aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream,
+static void aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -2106,7 +2102,7 @@ static int aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream,
aic3262->active_count--;
}
err:
- return 0;
+ return;
}
@@ -2547,13 +2543,13 @@ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
SOC_DAPM_SINGLE("MAL Switch", HP_AMP_CNTL_R1, 7, 1, 0),
SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 5, 1, 0),
SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", HP_AMP_CNTL_R2, 0,
- 0x7f, 1, lo_hp_tlv),
+ 0x7f, 0, lo_hp_tlv),
};
/* Right HPR Mixer */
static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", HP_AMP_CNTL_R3, 0,
- 0x7f, 1, lo_hp_tlv),
+ 0x7f, 0, lo_hp_tlv),
SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 2, 1, 0),
SOC_DAPM_SINGLE("RDAC Switch", HP_AMP_CNTL_R1, 4, 1, 0),
SOC_DAPM_SINGLE("MAR Switch", HP_AMP_CNTL_R1, 6, 1, 0),
@@ -3565,7 +3561,7 @@ void aic3262_write_reg_cache(struct snd_soc_codec *codec,
*----------------------------------------------------------------------------
*/
-u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
+unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg)
{
struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
u8 value;
@@ -3573,7 +3569,7 @@ u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
u16 *cache = codec->reg_cache;
u16 cmd;
u8 buffer[2];
- int rc;
+ int rc = 0;
reg = reg % 128;
if (reg >= AIC3262_CACHEREGNUM) {
@@ -3619,7 +3615,8 @@ u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
*
*----------------------------------------------------------------------------
*/
-int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value)
+int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
{
struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
u8 data[2];
@@ -3855,8 +3852,6 @@ int i2c_verify_book0(struct snd_soc_codec *codec)
static int aic3262_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 value;
switch (level) {
/* full On */
case SND_SOC_BIAS_ON:
@@ -4400,6 +4395,7 @@ static int aic3262_spi_write(struct spi_device *spi, const char *data, int len)
return len;
}
+#ifdef RUN_DELAYED_WORK
/*
* This function forces any delayed work to be queued and run.
*/
@@ -4418,6 +4414,8 @@ static int run_delayed_work(struct delayed_work *dwork)
}
return ret;
}
+#endif
+
static int __devinit aic3262_spi_probe(struct spi_device *spi)
{
int ret;
diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h
index a31cc9eca5ca..bfcbefc5c079 100644
--- a/sound/soc/codecs/tlv320aic326x.h
+++ b/sound/soc/codecs/tlv320aic326x.h
@@ -36,7 +36,7 @@
/* Enable register caching on write */
#define EN_REG_CACHE 1
-#define MULTIBYTE_CONFIG_SUPPORT
+//#define MULTIBYTE_CONFIG_SUPPORT
/*Setting all codec reg/write locally*/
/* This definition is added as the snd_ direct call are
@@ -45,12 +45,12 @@ page, so fix that before commenting this line*/
#define LOCAL_REG_ACCESS 1
/* Macro to enable the inclusion of tiload kernel driver */
-#define AIC3262_TiLoad
+//#define AIC3262_TiLoad
/* Macro enables or disables support for miniDSP in the driver */
/* Enable the AIC3262_TiLoad macro first before enabling these macros */
-#define CONFIG_MINI_DSP
+//#define CONFIG_MINI_DSP
/*#undef CONFIG_MINI_DSP*/
/* Enable or disable controls to have Input routing*/
@@ -657,11 +657,12 @@ extern int aic326x_headset_detect(struct snd_soc_codec *codec,
extern int aic326x_headset_button_init(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, int jack_type);
-extern u8 aic3262_read(struct snd_soc_codec *codec, u16 reg);
+extern unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg);
extern u16 aic3262_read_2byte(struct snd_soc_codec *codec, u16 reg);
extern int aic3262_reset_cache(struct snd_soc_codec *codec);
extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
-extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value);
+extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value);
extern void aic3262_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, u8 value);
extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
diff --git a/sound/soc/codecs/tlv320aic326x_mini-dsp.c b/sound/soc/codecs/tlv320aic326x_mini-dsp.c
index 6d55abb4dac8..0ef0fd09760c 100644
--- a/sound/soc/codecs/tlv320aic326x_mini-dsp.c
+++ b/sound/soc/codecs/tlv320aic326x_mini-dsp.c
@@ -601,25 +601,27 @@ struct process_flow{
int
set_minidsp_mode(struct snd_soc_codec *codec, int new_mode, int new_config)
{
-
- if (codec == NULL) {
- printk(KERN_INFO "%s codec is NULL\n",__func__);
- }
- struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct aic3262_priv *aic326x;
+ struct snd_soc_dapm_context *dapm;
struct process_flow * pflows = &miniDSP_programs[new_mode];
- u8 reg63, reg81, pll_pow, ndac_pow, mdac_pow, nadc_pow, madc_pow;
-
+ u8 pll_pow, ndac_pow, mdac_pow, nadc_pow;
u8 adc_status,dac_status;
- u8 reg, val;
- u8 shift;
- volatile u16 counter;
- int (*ptransfer)(struct snd_soc_codec *codec,
- reg_value *program_ptr,
- int size);
+ int (*ptransfer)(struct snd_soc_codec *codec, reg_value *program_ptr,
+ int size);
printk("%s:New Switch mode = %d New Config= %d\n", __func__, new_mode,new_config);
+
+ if (codec == NULL) {
+ printk(KERN_INFO "%s codec is NULL\n", __func__);
+ return 0;
+ }
+ aic326x = snd_soc_codec_get_drvdata(codec);
+ dapm = &codec->dapm;
+
+ printk(KERN_INFO "%s:New Switch mode = %d New Config= %d\n", __func__,
+ new_mode, new_config);
+
if (new_mode >= ARRAY_SIZE(miniDSP_programs))
return 0; // error condition
if (new_config > MAXCONFIG)
@@ -1231,7 +1233,7 @@ static int __new_control_put_minidsp_mux(struct snd_kcontrol *kcontrol,
int ret_val = -1, array_size;
control *array;
char **array_names;
- char *control_name, *control_name1, *control_name2;
+ char *control_name, *control_name1;
struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
i2c = codec->control_data;
diff --git a/sound/soc/codecs/tlv320aic326x_minidsp_config.c b/sound/soc/codecs/tlv320aic326x_minidsp_config.c
index e34ffbe2ca82..97a41c3ecf2b 100644
--- a/sound/soc/codecs/tlv320aic326x_minidsp_config.c
+++ b/sound/soc/codecs/tlv320aic326x_minidsp_config.c
@@ -347,17 +347,12 @@ int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec)
*---------------------------------------------------------------------------
*/
void minidsp_multiconfig(struct snd_soc_codec *codec,
- reg_value *a_patch, int a_size,
- reg_value *d_patch, int d_size)
+ reg_value *a_patch, int a_size, reg_value *d_patch, int d_size)
{
- struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
- int val1,val2;
int adc_status,dac_status;
int (*ptransfer)(struct snd_soc_codec *codec,
- reg_value *program_ptr,
- int size);
-
-printk("======in the config_multiconfiguration function==== \n");
+ reg_value *program_ptr, int size);
+ printk(KERN_INFO "======in the config_multiconfiguration function====\n");
#ifndef MULTIBYTE_I2C
ptransfer = byte_i2c_array_transfer;
#else
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 0218d6ce0557..2a2d16886989 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1404,6 +1404,7 @@ static struct {
{ 1500, 0x9, 0x2, 2 },
};
+#ifdef SYS_BCLK_RATIO
/* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */
static struct {
int ratio;
@@ -1427,6 +1428,7 @@ static struct {
{ 440, 19 },
{ 480, 20 },
};
+#endif
/* Sample rates for DSP */
static struct {
@@ -1778,9 +1780,6 @@ static int wm8903_resume(struct snd_soc_codec *codec)
if (wm8903->irq)
enable_irq(wm8903->irq);
- /* Bring the codec back up to standby first to minimise pop/clicks */
- wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/* Sync back everything else */
if (tmp_cache) {
for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
@@ -1791,6 +1790,9 @@ static int wm8903_resume(struct snd_soc_codec *codec)
dev_err(codec->dev, "Failed to allocate temporary cache\n");
}
+ /* Bring the codec back up to standby first to minimise pop/clicks */
+ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
return 0;
}
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index de9abd032fd4..5cfcc655e95f 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -180,13 +180,8 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
sg_dma_len(&sg) = size;
sg_dma_address(&sg) = buff;
-<<<<<<< HEAD
- desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
- &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-=======
desc = dmaengine_prep_slave_sg(siu_stream->chan,
&sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (!desc) {
dev_err(dev, "Failed to allocate dma descriptor\n");
return -ENOMEM;
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index d546046d1e1d..9c4346aa265c 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -2,6 +2,7 @@ GCOV_PROFILE := y
# Tegra platform Support
snd-soc-tegra-pcm-objs := tegra_pcm.o
+snd-soc-tegra-tdm-pcm-objs := tegra_tdm_pcm.o
snd-soc-tegra20-spdif-objs := tegra20_spdif.o
snd-soc-tegra-utils-objs += tegra_asoc_utils.o
snd-soc-tegra20-das-objs := tegra20_das.o
@@ -13,6 +14,7 @@ snd-soc-tegra30-dam-objs := tegra30_dam.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-tdm-pcm.o
obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index e6de1c07a399..d90c0991ed65 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -191,8 +191,9 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 reg;
int ret, sample_size, srate, i2sclock, bitcnt, i2sclk_div;
+ u32 bit_format = i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_MASK;
- if ((i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_I2S) &&
+ if ((bit_format == TEGRA20_I2S_CTRL_BIT_FORMAT_I2S) &&
(params_channels(params) != 2)) {
dev_err(dev, "Only Stereo is supported in I2s mode\n");
return -EINVAL;
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 710d9465b4b0..30b7e481acc4 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -116,6 +116,15 @@ void tegra30_ahub_disable_clocks(void)
clk_disable(ahub->clk_d_audio);
}
+/*
+ * for TDM mode, ahub has to run faster than I2S controller. This will avoid
+ * FIFO overflow/underflow, the causes of slot-hopping symptoms
+ */
+void tegra30_ahub_clock_set_rate(int rate)
+{
+ clk_set_rate(ahub->clk_d_audio, rate);
+}
+
#ifdef CONFIG_DEBUG_FS
static inline u32 tegra30_ahub_read(u32 space, u32 reg)
{
@@ -272,6 +281,75 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
return 0;
}
+int tegra30_ahub_rx_fifo_is_enabled(int i2s_id)
+{
+ int val, mask;
+
+ val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS);
+ mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED << (i2s_id*2));
+ val &= mask;
+ return val;
+}
+
+int tegra30_ahub_tx_fifo_is_enabled(int i2s_id)
+{
+ int val, mask;
+
+ val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS);
+ mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED << (i2s_id*2));
+ val &= mask;
+
+ return val;
+}
+
+int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif,
+ unsigned int pack_mode)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+ int reg, val;
+
+ tegra30_ahub_enable_clocks();
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+
+ val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK;
+ val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN;
+
+ if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16) ||
+ (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4))
+ val |= (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
+ pack_mode);
+ tegra30_apbif_write(reg, val);
+ tegra30_ahub_disable_clocks();
+
+ return 0;
+}
+
+int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif,
+ unsigned int pack_mode)
+{
+ int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+ int reg, val;
+
+ tegra30_ahub_enable_clocks();
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+
+ val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK;
+ val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN;
+
+ if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16) ||
+ (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4))
+ val |= (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
+ pack_mode);
+ tegra30_apbif_write(reg, val);
+ tegra30_ahub_disable_clocks();
+
+ return 0;
+}
+
int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
{
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
@@ -480,6 +558,54 @@ int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif,
return 0;
}
+int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif,
+ unsigned int audio_bits,
+ unsigned int client_bits)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+ unsigned int reg, val;
+
+ tegra30_ahub_enable_clocks();
+
+ reg = TEGRA30_AHUB_CIF_RX_CTRL +
+ (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK |
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK);
+ val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT);
+ tegra30_apbif_write(reg, val);
+
+ tegra30_ahub_disable_clocks();
+
+ return 0;
+}
+
+int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif,
+ unsigned int audio_bits,
+ unsigned int client_bits)
+{
+ int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+ unsigned int reg, val;
+
+ tegra30_ahub_enable_clocks();
+
+ reg = TEGRA30_AHUB_CIF_TX_CTRL +
+ (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK |
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK);
+ val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT);
+
+ tegra30_apbif_write(reg, val);
+
+ tegra30_ahub_disable_clocks();
+
+ return 0;
+}
+
+
static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
{
struct resource *res0, *res1, *region;
@@ -507,6 +633,7 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
goto err_free;
}
clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio));
+
while (clkm_rate > 12000000)
clkm_rate >>= 1;
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 7de1b7c86c7f..8dc27abc5aed 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -464,6 +464,7 @@ enum tegra30_ahub_rxcif {
extern void tegra30_ahub_enable_clocks(void);
extern void tegra30_ahub_disable_clocks(void);
+extern void tegra30_ahub_clock_set_rate(int rate);
extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
unsigned long *fiforeg,
@@ -471,8 +472,13 @@ extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
extern int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif,
unsigned int audio_ch,
unsigned int client_ch);
+extern int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif,
+ unsigned int audio_bits,
+ unsigned int client_bits);
extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif,
+ unsigned int pack_mode);
extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
@@ -481,14 +487,22 @@ extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
extern int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif,
unsigned int audio_ch,
unsigned int client_ch);
+extern int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif,
+ unsigned int audio_bits,
+ unsigned int client_bits);
extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif,
+ unsigned int pack_mode);
extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_rx_fifo_is_enabled(int i2s_id);
+extern int tegra30_ahub_tx_fifo_is_enabled(int i2s_id);
+
#ifdef CONFIG_PM
extern int tegra30_ahub_apbif_resume(void);
#endif
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 02d1038ea36e..449359837efb 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -36,6 +36,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include <mach/iomap.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -280,6 +281,194 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
return 0;
}
+static void tegra30_i2s_set_channel_bit_count(struct tegra30_i2s *i2s,
+ int i2sclock, int srate)
+{
+ int sym_bitclk, bitcnt;
+ u32 val;
+
+ bitcnt = (i2sclock / (2 * srate)) - 1;
+ sym_bitclk = !(i2sclock % (2 * srate));
+
+ val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+ if (!sym_bitclk)
+ val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
+
+ tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
+}
+
+static void tegra30_i2s_set_data_offset(struct tegra30_i2s *i2s)
+{
+ u32 val;
+ int rx_data_offset = i2s->dsp_config.rx_data_offset;
+ int tx_data_offset = i2s->dsp_config.tx_data_offset;
+
+ val = (rx_data_offset <<
+ TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
+ (tx_data_offset <<
+ TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
+
+ tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+}
+
+static void tegra30_i2s_set_slot_control(struct tegra30_i2s *i2s, int stream)
+{
+ u32 val;
+ int tx_mask = i2s->dsp_config.tx_mask;
+ int rx_mask = i2s->dsp_config.rx_mask;
+
+ val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK;
+ val |= (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT);
+ } else {
+ val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK;
+ val |= (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT);
+ }
+
+ val &= ~TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK;
+ val |= (i2s->dsp_config.num_slots - 1)
+ << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT;
+
+ tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val);
+}
+
+static int tegra30_i2s_tdm_setup_clocks(struct device *dev,
+ struct tegra30_i2s *i2s, int *i2sclock)
+{
+ int ret;
+
+ if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) {
+
+ ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0);
+ if (ret) {
+ dev_err(dev, "Can't set parent of I2S clock\n");
+ return ret;
+ }
+ ret = clk_set_rate(i2s->clk_i2s, *i2sclock);
+ if (ret) {
+ dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+ return ret;
+ }
+ } else {
+
+ ret = clk_set_rate(i2s->clk_i2s_sync, *i2sclock);
+ if (ret) {
+ dev_err(dev, "Can't set I2S sync clock rate\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock);
+ if (ret) {
+ dev_err(dev, "Can't set audio2x clock rate\n");
+ return ret;
+ }
+
+ ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x);
+ if (ret) {
+ dev_err(dev, "Can't set parent of audio2x clock\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+
+static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = substream->pcm->card->dev;
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 val;
+ int i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits;
+ int i2sclock, srate;
+ int ret;
+
+ srate = params_rate(params);
+
+ i2sclock = srate *
+ i2s->dsp_config.num_slots *
+ i2s->dsp_config.slot_width;
+
+ ret = tegra30_i2s_tdm_setup_clocks(dev, i2s, &i2sclock);
+ if (ret)
+ return -EINVAL;
+
+ /* Run ahub clock greater than i2sclock */
+ tegra30_ahub_clock_set_rate(i2sclock*2);
+
+ tegra30_i2s_enable_clocks(i2s);
+
+ tegra30_i2s_set_channel_bit_count(i2s, i2sclock*2, srate);
+
+ i2s_client_ch = i2s->dsp_config.num_slots;
+ i2s_audio_ch = i2s->dsp_config.num_slots;
+
+ i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
+ switch (i2s->dsp_config.slot_width) {
+ case 16:
+ i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ i2s_client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16;
+ break;
+ case 32:
+ i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_32;
+ i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32;
+ break;
+ }
+
+ val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ ((i2s_audio_ch - 1) <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ ((i2s_client_ch - 1) <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ (i2s_audio_bits <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ (i2s_client_bits <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val);
+
+ tegra30_ahub_set_tx_cif_channels(i2s->txcif,
+ i2s_audio_ch,
+ i2s_client_ch);
+ tegra30_ahub_set_tx_cif_bits(i2s->txcif,
+ i2s_audio_bits,
+ i2s_client_bits);
+ tegra30_ahub_set_tx_fifo_pack_mode(i2s->txcif, 0);
+
+ } else {
+ val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val);
+
+ tegra30_ahub_set_rx_cif_channels(i2s->rxcif,
+ i2s_audio_ch,
+ i2s_client_ch);
+ tegra30_ahub_set_rx_cif_bits(i2s->rxcif,
+ i2s_audio_bits,
+ i2s_client_bits);
+ tegra30_ahub_set_rx_fifo_pack_mode(i2s->rxcif, 0);
+ }
+
+ tegra30_i2s_set_slot_control(i2s, substream->stream);
+
+ tegra30_i2s_set_data_offset(i2s);
+
+ i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK;
+ i2s->reg_ch_ctrl |= (i2s->dsp_config.slot_width - 1) <<
+ TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl);
+
+ tegra30_i2s_disable_clocks(i2s);
+
+ return 0;
+}
+
static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -300,6 +489,12 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ /* TDM mode */
+ if ((i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) &&
+ (i2s->dsp_config.slot_width > 2))
+ return tegra30_i2s_tdm_hw_params(substream, params, dai);
+
+
srate = params_rate(params);
if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) {
@@ -423,12 +618,15 @@ static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s)
static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
{
- tegra30_ahub_disable_tx_fifo(i2s->txcif);
+ int dcnt = 10;
/* if this is the only user of i2s tx then disable it*/
+ tegra30_ahub_disable_tx_fifo(i2s->txcif);
if (i2s->playback_ref_count == 1) {
i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
}
+ while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--)
+ udelay(100);
}
static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
@@ -442,11 +640,14 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
{
+ int dcnt = 10;
tegra30_ahub_disable_rx_fifo(i2s->rxcif);
if (!i2s->is_call_mode_rec) {
i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
}
+ while (tegra30_ahub_rx_fifo_is_enabled(i2s->id) && dcnt--)
+ udelay(100);
}
static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -500,6 +701,33 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
tegra30_i2s_disable_clocks(i2s);
#endif
+ /* Default values for DSP mode */
+ i2s->dsp_config.num_slots = 1;
+ i2s->dsp_config.slot_width = 2;
+ i2s->dsp_config.tx_mask = 1;
+ i2s->dsp_config.rx_mask = 1;
+ i2s->dsp_config.rx_data_offset = 1;
+ i2s->dsp_config.tx_data_offset = 1;
+
+
+ return 0;
+}
+
+int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots,
+ int slot_width)
+{
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+
+ i2s->dsp_config.num_slots = slots;
+ i2s->dsp_config.slot_width = slot_width;
+ i2s->dsp_config.tx_mask = tx_mask;
+ i2s->dsp_config.rx_mask = rx_mask;
+ i2s->dsp_config.rx_data_offset = 0;
+ i2s->dsp_config.tx_data_offset = 0;
+
return 0;
}
@@ -534,6 +762,7 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
.set_fmt = tegra30_i2s_set_fmt,
.hw_params = tegra30_i2s_hw_params,
.trigger = tegra30_i2s_trigger,
+ .set_tdm_slot = tegra30_i2s_set_tdm_slot,
};
#define TEGRA30_I2S_DAI(id) \
@@ -543,13 +772,13 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
.resume = tegra30_i2s_resume, \
.playback = { \
.channels_min = 1, \
- .channels_max = 2, \
+ .channels_max = 16, \
.rates = SNDRV_PCM_RATE_8000_96000, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
}, \
.capture = { \
.channels_min = 1, \
- .channels_max = 2, \
+ .channels_max = 16, \
.rates = SNDRV_PCM_RATE_8000_96000, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
}, \
@@ -726,10 +955,7 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
TEGRA30_DAM_CHIN0_SRC);
- /* if this is the only user of i2s tx then enable it*/
- if (codec_i2s->playback_ref_count == 1)
- codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
-
+ codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL,
codec_i2s->reg_ctrl);
@@ -827,7 +1053,6 @@ static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev)
ret = PTR_ERR(i2s->clk_i2s);
goto exit;
}
-
i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync");
if (IS_ERR(i2s->clk_i2s_sync)) {
dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n");
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index b9baddd5db8e..0992bf0d5b17 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -176,7 +176,7 @@
/* Number of slots in frame, minus 1 */
#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16
#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7
-#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT)
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT)
/* TDM mode slot enable bitmask */
#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8
@@ -231,6 +231,16 @@
/* Number of i2s controllers*/
#define TEGRA30_NR_I2S_IFC 5
+struct dsp_config_t {
+ int num_slots;
+ int rx_mask;
+ int tx_mask;
+ int slot_width;
+ int rx_data_offset;
+ int tx_data_offset;
+};
+
+
struct tegra30_i2s {
int id;
struct clk *clk_i2s;
@@ -254,6 +264,8 @@ struct tegra30_i2s {
#endif
int call_record_dam_ifc;
int is_call_mode_rec;
+
+ struct dsp_config_t dsp_config;
};
struct codec_config {
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c
index 93013c5e99b6..a5c6fc0aecb7 100644
--- a/sound/soc/tegra/tegra_aic326x.c
+++ b/sound/soc/tegra/tegra_aic326x.c
@@ -1142,8 +1142,10 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
struct snd_soc_card *card = &snd_soc_tegra_aic326x;
struct tegra_aic326x *machine;
struct tegra_asoc_platform_data *pdata;
- int ret, i;
-
+ int ret;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ int i;
+#endif
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "No platform data supplied\n");
@@ -1158,7 +1160,7 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
machine->pdata = pdata;
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index 04e7e3c15cd0..b134f0808afa 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -153,12 +153,12 @@ int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data)
EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable);
int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
- struct device *dev)
+ struct device *dev, struct snd_soc_card *card)
{
int ret;
- int rate;
data->dev = dev;
+ data->card = card;
data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1");
if (IS_ERR(data->clk_pll_p_out1)) {
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 1c4e521cb4ba..512df0d54eb1 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -31,6 +31,7 @@ struct device;
struct tegra_asoc_utils_data {
struct device *dev;
+ struct snd_soc_card *card;
struct clk *clk_pll_a;
struct clk *clk_pll_a_out0;
struct clk *clk_cdev1;
@@ -47,7 +48,7 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data,
int lock);
int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
- struct device *dev);
+ struct device *dev, struct snd_soc_card *card);
void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data);
int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data);
diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c
index 9546af83b39d..8c0e3935ad02 100644
--- a/sound/soc/tegra/tegra_max98088.c
+++ b/sound/soc/tegra/tegra_max98088.c
@@ -96,6 +96,7 @@ struct tegra_max98088 {
#endif
enum snd_soc_bias_level bias_level;
struct snd_soc_card *pcard;
+ volatile int clock_enabled;
};
static int tegra_call_mode_info(struct snd_kcontrol *kcontrol,
@@ -559,7 +560,7 @@ static void tegra_max98088_shutdown(struct snd_pcm_substream *substream)
} else {
if (!i2s->is_call_mode_rec)
- return 0;
+ return;
i2s->is_call_mode_rec = 0;
@@ -926,6 +927,7 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd)
machine->pcard = card;
machine->bias_level = SND_SOC_BIAS_STANDBY;
+ machine->clock_enabled = 1;
if (gpio_is_valid(pdata->gpio_spkr_en)) {
ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
@@ -1065,25 +1067,30 @@ static struct snd_soc_dai_link tegra_max98088_dai[NUM_DAI_LINKS] = {
};
static int tegra30_soc_set_bias_level(struct snd_soc_card *card,
- enum snd_soc_bias_level level)
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
if (machine->bias_level == SND_SOC_BIAS_OFF &&
- level != SND_SOC_BIAS_OFF)
+ level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) {
+ machine->clock_enabled = 1;
tegra_asoc_utils_clk_enable(&machine->util_data);
+ machine->bias_level = level;
+ }
return 0;
}
static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card,
- enum snd_soc_bias_level level)
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
if (machine->bias_level != SND_SOC_BIAS_OFF &&
- level == SND_SOC_BIAS_OFF)
+ level == SND_SOC_BIAS_OFF && (machine->clock_enabled)) {
+ machine->clock_enabled = 0;
tegra_asoc_utils_clk_disable(&machine->util_data);
+ }
machine->bias_level = level;
@@ -1119,7 +1126,7 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev)
machine->pdata = pdata;
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
@@ -1156,6 +1163,7 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev)
tegra_max98088_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id];
#endif
+ card->dapm.idle_bias_off = 1;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c
index 2104ba849cd3..95295ef4151e 100644
--- a/sound/soc/tegra/tegra_max98095.c
+++ b/sound/soc/tegra/tegra_max98095.c
@@ -630,7 +630,7 @@ static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev)
machine->pdata = pdata;
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c
index 27a1ea590340..9506a1c842df 100644
--- a/sound/soc/tegra/tegra_p1852.c
+++ b/sound/soc/tegra/tegra_p1852.c
@@ -201,7 +201,7 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev)
pdata->codec_info[i].name;
}
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 00bd7aa2e59d..1b4b949841aa 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -2,7 +2,7 @@
* tegra_pcm.c - Tegra PCM driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
*
* Based on code copyright/by:
*
@@ -29,6 +29,7 @@
*
*/
+#include <asm/mach-types.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
@@ -66,7 +67,8 @@ static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
unsigned long addr;
dma_req = &prtd->dma_req[prtd->dma_req_idx];
- prtd->dma_req_idx = 1 - prtd->dma_req_idx;
+ if (++prtd->dma_req_idx >= prtd->dma_req_count)
+ prtd->dma_req_idx -= prtd->dma_req_count;
addr = buf->addr + prtd->dma_pos;
prtd->dma_pos += dma_req->size;
@@ -130,13 +132,16 @@ static void setup_dma_rx_request(struct tegra_dma_req *req,
req->req_sel = dmap->req_sel;
}
-static int tegra_pcm_open(struct snd_pcm_substream *substream)
+int tegra_pcm_allocate(struct snd_pcm_substream *substream,
+ int dma_mode,
+ const struct snd_pcm_hardware *pcm_hardware)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct tegra_pcm_dma_params * dmap;
int ret = 0;
+ int i = 0;
prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL);
if (prtd == NULL)
@@ -148,13 +153,14 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
spin_lock_init(&prtd->lock);
dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ prtd->dma_req_count = MAX_DMA_REQ_COUNT;
if (dmap) {
- prtd->dma_req[0].dev = prtd;
- prtd->dma_req[1].dev = prtd;
+ for (i = 0; i < prtd->dma_req_count; i++)
+ prtd->dma_req[i].dev = prtd;
prtd->dma_chan = tegra_dma_allocate_channel(
- TEGRA_DMA_MODE_CONTINUOUS_SINGLE,
+ dma_mode,
"pcm");
if (prtd->dma_chan == NULL) {
ret = -ENOMEM;
@@ -163,7 +169,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
}
/* Set HW params now that initialization is complete */
- snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
+ snd_soc_set_runtime_hwparams(substream, pcm_hardware);
/* Ensure period size is multiple of 8 */
ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -189,7 +195,15 @@ err:
return ret;
}
-static int tegra_pcm_close(struct snd_pcm_substream *substream)
+static int tegra_pcm_open(struct snd_pcm_substream *substream)
+{
+ return tegra_pcm_allocate(substream,
+ TEGRA_DMA_MODE_CONTINUOUS_SINGLE,
+ &tegra_pcm_hardware);
+
+}
+
+int tegra_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
@@ -202,44 +216,55 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
+int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct tegra_pcm_dma_params * dmap;
+ int i;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ /* Limit dma_req_count to period count */
+ if (prtd->dma_req_count > params_periods(params))
+ prtd->dma_req_count = params_periods(params);
dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (dmap) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- setup_dma_tx_request(&prtd->dma_req[0], dmap);
- setup_dma_tx_request(&prtd->dma_req[1], dmap);
+ for (i = 0; i < prtd->dma_req_count; i++)
+ setup_dma_tx_request(&prtd->dma_req[i], dmap);
} else {
- setup_dma_rx_request(&prtd->dma_req[0], dmap);
- setup_dma_rx_request(&prtd->dma_req[1], dmap);
+ for (i = 0; i < prtd->dma_req_count; i++)
+ setup_dma_rx_request(&prtd->dma_req[i], dmap);
}
}
- prtd->dma_req[0].size = params_period_bytes(params);
- prtd->dma_req[1].size = prtd->dma_req[0].size;
+ for (i = 0; i < prtd->dma_req_count; i++)
+ prtd->dma_req[i].size = params_period_bytes(params);
return 0;
}
-static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
+int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
-static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct tegra_pcm_dma_params * dmap;
unsigned long flags;
+ int i;
+
+ dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ if (!dmap)
+ return 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -253,8 +278,8 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock_irqsave(&prtd->lock, flags);
prtd->running = 1;
spin_unlock_irqrestore(&prtd->lock, flags);
- tegra_pcm_queue_dma(prtd);
- tegra_pcm_queue_dma(prtd);
+ for (i = 0; i < prtd->dma_req_count; i++)
+ tegra_pcm_queue_dma(prtd);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -263,10 +288,11 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
prtd->running = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
tegra_dma_cancel(prtd->dma_chan);
- if (prtd->dma_req[0].status == -TEGRA_DMA_REQ_ERROR_ABORTED)
- prtd->dma_req[0].complete(&prtd->dma_req[0]);
- if (prtd->dma_req[1].status == -TEGRA_DMA_REQ_ERROR_ABORTED)
- prtd->dma_req[1].complete(&prtd->dma_req[1]);
+ for (i = 0; i < prtd->dma_req_count; i++) {
+ if (prtd->dma_req[i].status ==
+ -TEGRA_DMA_REQ_ERROR_ABORTED)
+ prtd->dma_req[i].complete(&prtd->dma_req[i]);
+ }
break;
default:
return -EINVAL;
@@ -275,7 +301,7 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}
-static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
@@ -288,7 +314,7 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
bytes_to_frames(runtime, dma_transfer_count);
}
-static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
+int tegra_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -310,11 +336,11 @@ static struct snd_pcm_ops tegra_pcm_ops = {
.mmap = tegra_pcm_mmap,
};
-static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+ int stream , size_t size)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = tegra_pcm_hardware.buffer_bytes_max;
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
@@ -329,7 +355,7 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
return 0;
}
-static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
@@ -349,7 +375,7 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
static u64 tegra_dma_mask = DMA_BIT_MASK(32);
-static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
+int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd, size_t size)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai;
@@ -363,14 +389,16 @@ static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
if (dai->driver->playback.channels_min) {
ret = tegra_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
+ SNDRV_PCM_STREAM_PLAYBACK,
+ size);
if (ret)
goto err;
}
if (dai->driver->capture.channels_min) {
ret = tegra_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
+ SNDRV_PCM_STREAM_CAPTURE,
+ size);
if (ret)
goto err_free_play;
}
@@ -383,16 +411,31 @@ err:
return ret;
}
-static void tegra_pcm_free(struct snd_pcm *pcm)
+int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ return tegra_pcm_dma_allocate(rtd ,
+ tegra_pcm_hardware.buffer_bytes_max);
+}
+
+void tegra_pcm_free(struct snd_pcm *pcm)
{
tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
}
+static int tegra_pcm_probe(struct snd_soc_platform *platform)
+{
+ if(machine_is_kai() || machine_is_tegra_enterprise())
+ platform->dapm.idle_bias_off = 1;
+
+ return 0;
+}
+
struct snd_soc_platform_driver tegra_pcm_platform = {
.ops = &tegra_pcm_ops,
.pcm_new = tegra_pcm_new,
.pcm_free = tegra_pcm_free,
+ .probe = tegra_pcm_probe,
};
static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index dbb90339fe0d..7fe22788004b 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -33,6 +33,8 @@
#include <mach/dma.h>
+#define MAX_DMA_REQ_COUNT 2
+
struct tegra_pcm_dma_params {
unsigned long addr;
unsigned long wrap;
@@ -48,8 +50,24 @@ struct tegra_runtime_data {
int dma_pos_end;
int period_index;
int dma_req_idx;
- struct tegra_dma_req dma_req[2];
+ struct tegra_dma_req dma_req[MAX_DMA_REQ_COUNT];
struct tegra_dma_channel *dma_chan;
+ int dma_req_count;
};
+int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+int tegra_pcm_allocate(struct snd_pcm_substream *substream,
+ int dma_mode,
+ const struct snd_pcm_hardware *pcm_hardware);
+int tegra_pcm_close(struct snd_pcm_substream *substream);
+int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+int tegra_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma);
+int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd, size_t size);
+void tegra_pcm_free(struct snd_pcm *pcm);
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream);
+int tegra_pcm_hw_free(struct snd_pcm_substream *substream);
+
#endif
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index e7d58803f7c9..231b0ee61308 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -69,6 +69,8 @@ struct tegra_rt5640 {
#ifdef CONFIG_SWITCH
int jack_status;
#endif
+ enum snd_soc_bias_level bias_level;
+ volatile int clock_enabled;
};
static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
@@ -279,7 +281,7 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self,
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
struct tegra_rt5640_platform_data *pdata = machine->pdata;
enum headset_state state = BIT_NO_HEADSET;
- unsigned char status_jack;
+ unsigned char status_jack = 0;
if (jack == &tegra_rt5640_hp_jack) {
if (action) {
@@ -532,6 +534,9 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
machine->gpio_requested |= GPIO_HP_DET;
}
+ machine->bias_level = SND_SOC_BIAS_STANDBY;
+ machine->clock_enabled = 1;
+
ret = snd_soc_add_controls(codec, cardhu_controls,
ARRAY_SIZE(cardhu_controls));
if (ret < 0)
@@ -582,10 +587,58 @@ static struct snd_soc_dai_link tegra_rt5640_dai[] = {
},
};
+static int tegra_rt5640_resume_pre(struct snd_soc_card *card)
+{
+ int val;
+ struct snd_soc_jack_gpio *gpio = &tegra_rt5640_hp_jack_gpio;
+
+ if (gpio_is_valid(gpio->gpio)) {
+ val = gpio_get_value(gpio->gpio);
+ val = gpio->invert ? !val : val;
+ snd_soc_jack_report(gpio->jack, val, gpio->report);
+ }
+
+ return 0;
+}
+
+static int tegra_rt5640_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+ struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+ if (machine->bias_level == SND_SOC_BIAS_OFF &&
+ level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) {
+ machine->clock_enabled = 1;
+ tegra_asoc_utils_clk_enable(&machine->util_data);
+ machine->bias_level = level;
+ }
+
+ return 0;
+}
+
+static int tegra_rt5640_set_bias_level_post(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+ struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+ if (machine->bias_level != SND_SOC_BIAS_OFF &&
+ level == SND_SOC_BIAS_OFF && machine->clock_enabled) {
+ machine->clock_enabled = 0;
+ tegra_asoc_utils_clk_disable(&machine->util_data);
+ }
+
+ machine->bias_level = level;
+
+ return 0 ;
+}
+
static struct snd_soc_card snd_soc_tegra_rt5640 = {
.name = "tegra-rt5640",
.dai_link = tegra_rt5640_dai,
.num_links = ARRAY_SIZE(tegra_rt5640_dai),
+ .resume_pre = tegra_rt5640_resume_pre,
+ .set_bias_level = tegra_rt5640_set_bias_level,
+ .set_bias_level_post = tegra_rt5640_set_bias_level_post,
};
static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
@@ -614,7 +667,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
machine->pdata = pdata;
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
@@ -643,7 +696,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
-
+ card->dapm.idle_bias_off = 1;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
diff --git a/sound/soc/tegra/tegra_tdm_pcm.c b/sound/soc/tegra/tegra_tdm_pcm.c
new file mode 100644
index 000000000000..ae33bdbc588c
--- /dev/null
+++ b/sound/soc/tegra/tegra_tdm_pcm.c
@@ -0,0 +1,160 @@
+/*
+ * tegra_tdm_pcm.c - Tegra TDM PCM driver
+ *
+ * Author: Nitin Pai <npai@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ * Stephen Warren <swarren@nvidia.com>
+ * Vijay Mali <vmali@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_pcm.h"
+
+#define DRV_NAME "tegra-tdm-pcm-audio"
+
+static const struct snd_pcm_hardware tegra_tdm_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_INTERLEAVED,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 8,
+ .channels_max = 16,
+ .period_bytes_min = 16 * 1024,
+ .period_bytes_max = 16 * 1024,
+ .periods_min = 4,
+ .periods_max = 4,
+ .buffer_bytes_max = 16 * 4 * 1024,
+ .fifo_size = 4,
+};
+
+static int tegra_tdm_pcm_open(struct snd_pcm_substream *substream)
+{
+ return tegra_pcm_allocate(substream,
+ TEGRA_DMA_MODE_CONTINUOUS_DOUBLE,
+ &tegra_tdm_pcm_hardware);
+
+}
+
+static int tegra_tdm_pcm_close(struct snd_pcm_substream *substream)
+{
+ return tegra_pcm_close(substream);
+}
+
+static int tegra_tdm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return tegra_pcm_hw_params(substream, params);
+}
+
+static int tegra_tdm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return tegra_pcm_hw_free(substream);
+}
+
+static int tegra_tdm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ return tegra_pcm_trigger(substream, cmd);
+}
+
+static int tegra_tdm_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ return tegra_pcm_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops tegra_tdm_pcm_ops = {
+ .open = tegra_tdm_pcm_open,
+ .close = tegra_tdm_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = tegra_tdm_pcm_hw_params,
+ .hw_free = tegra_tdm_pcm_hw_free,
+ .trigger = tegra_tdm_pcm_trigger,
+ .pointer = tegra_pcm_pointer,
+ .mmap = tegra_tdm_pcm_mmap,
+};
+
+static int tegra_tdm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ return tegra_pcm_dma_allocate(rtd ,
+ tegra_tdm_pcm_hardware.buffer_bytes_max);
+}
+
+static void tegra_tdm_pcm_free(struct snd_pcm *pcm)
+{
+ return tegra_pcm_free(pcm);
+}
+
+struct snd_soc_platform_driver tegra_tdm_pcm_platform = {
+ .ops = &tegra_tdm_pcm_ops,
+ .pcm_new = tegra_tdm_pcm_new,
+ .pcm_free = tegra_tdm_pcm_free,
+};
+
+static int __devinit tegra_tdm_pcm_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &tegra_tdm_pcm_platform);
+}
+
+static int __devexit tegra_tdm_pcm_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver tegra_tdm_pcm_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_tdm_pcm_platform_probe,
+ .remove = __devexit_p(tegra_tdm_pcm_platform_remove),
+};
+
+static int __init snd_tegra_tdm_pcm_init(void)
+{
+ return platform_driver_register(&tegra_tdm_pcm_driver);
+}
+module_init(snd_tegra_tdm_pcm_init);
+
+static void __exit snd_tegra_tdm_pcm_exit(void)
+{
+ platform_driver_unregister(&tegra_tdm_pcm_driver);
+}
+module_exit(snd_tegra_tdm_pcm_exit);
+
+MODULE_AUTHOR("Nitin Pai <npai@nvidia.com>");
+MODULE_DESCRIPTION("Tegra PCM ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index 2e532fcd1e46..795356875ba4 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -872,7 +872,7 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
machine->pdata = pdata;
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 55e4f61edfd2..ce608b007bef 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -805,7 +805,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
machine->pdata = pdata;
- ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 8fc07e9adf2e..660479b89478 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -163,7 +163,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
+ ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev, card);
if (ret)
goto err_free_trimslice;